nodejs-insta-private-api-mqt 1.3.70

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.
Files changed (240) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +3677 -0
  3. package/dist/constants/constants.js +342 -0
  4. package/dist/constants/index.js +58 -0
  5. package/dist/core/client.js +419 -0
  6. package/dist/core/nav-chain.js +282 -0
  7. package/dist/core/repository.js +7 -0
  8. package/dist/core/request.js +390 -0
  9. package/dist/core/state.js +1473 -0
  10. package/dist/core/utils.js +786 -0
  11. package/dist/downloadMedia.js +381 -0
  12. package/dist/errors/index.d.ts +16 -0
  13. package/dist/errors/index.js +38 -0
  14. package/dist/errors/index.js.map +1 -0
  15. package/dist/extend.js +167 -0
  16. package/dist/fbns/fbns.client.d.ts +32 -0
  17. package/dist/fbns/fbns.client.events.d.ts +41 -0
  18. package/dist/fbns/fbns.client.events.js +3 -0
  19. package/dist/fbns/fbns.client.events.js.map +1 -0
  20. package/dist/fbns/fbns.client.js +252 -0
  21. package/dist/fbns/fbns.client.js.map +1 -0
  22. package/dist/fbns/fbns.device-auth.d.ts +17 -0
  23. package/dist/fbns/fbns.device-auth.js +54 -0
  24. package/dist/fbns/fbns.device-auth.js.map +1 -0
  25. package/dist/fbns/fbns.types.d.ts +83 -0
  26. package/dist/fbns/fbns.types.js +3 -0
  27. package/dist/fbns/fbns.types.js.map +1 -0
  28. package/dist/fbns/fbns.utilities.d.ts +2 -0
  29. package/dist/fbns/fbns.utilities.js +79 -0
  30. package/dist/fbns/fbns.utilities.js.map +1 -0
  31. package/dist/fbns/index.d.ts +4 -0
  32. package/dist/fbns/index.js +21 -0
  33. package/dist/fbns/index.js.map +1 -0
  34. package/dist/index.js +139 -0
  35. package/dist/mqtt-shim.d.ts +96 -0
  36. package/dist/mqtt-shim.js +15 -0
  37. package/dist/mqttot/index.d.ts +4 -0
  38. package/dist/mqttot/index.js +21 -0
  39. package/dist/mqttot/index.js.map +1 -0
  40. package/dist/mqttot/mqttot.client.d.ts +39 -0
  41. package/dist/mqttot/mqttot.client.js +318 -0
  42. package/dist/mqttot/mqttot.client.js.map +1 -0
  43. package/dist/mqttot/mqttot.connect.request.packet.d.ts +7 -0
  44. package/dist/mqttot/mqttot.connect.request.packet.js +9 -0
  45. package/dist/mqttot/mqttot.connect.request.packet.js.map +1 -0
  46. package/dist/mqttot/mqttot.connect.response.packet.d.ts +7 -0
  47. package/dist/mqttot/mqttot.connect.response.packet.js +24 -0
  48. package/dist/mqttot/mqttot.connect.response.packet.js.map +1 -0
  49. package/dist/mqttot/mqttot.connection.d.ts +57 -0
  50. package/dist/mqttot/mqttot.connection.js +79 -0
  51. package/dist/mqttot/mqttot.connection.js.map +1 -0
  52. package/dist/package.json +59 -0
  53. package/dist/realtime/commands/commands.d.ts +15 -0
  54. package/dist/realtime/commands/commands.js +71 -0
  55. package/dist/realtime/commands/commands.js.map +1 -0
  56. package/dist/realtime/commands/direct.commands.d.ts +75 -0
  57. package/dist/realtime/commands/direct.commands.js +417 -0
  58. package/dist/realtime/commands/direct.commands.js.map +1 -0
  59. package/dist/realtime/commands/enhanced.direct.commands.js +1731 -0
  60. package/dist/realtime/commands/enhanced.direct.commands.js.bak +967 -0
  61. package/dist/realtime/commands/index.d.ts +2 -0
  62. package/dist/realtime/commands/index.js +20 -0
  63. package/dist/realtime/commands/index.js.map +1 -0
  64. package/dist/realtime/delta-sync.manager.js +293 -0
  65. package/dist/realtime/features/dm-sender.js +88 -0
  66. package/dist/realtime/features/error-handler.js +185 -0
  67. package/dist/realtime/features/gap-handler.js +61 -0
  68. package/dist/realtime/features/persistent-logger.js +186 -0
  69. package/dist/realtime/features/presence.manager.js +66 -0
  70. package/dist/realtime/features/session-health-monitor.js +345 -0
  71. package/dist/realtime/index.js +30 -0
  72. package/dist/realtime/messages/app-presence.event.d.ts +9 -0
  73. package/dist/realtime/messages/app-presence.event.js +3 -0
  74. package/dist/realtime/messages/app-presence.event.js.map +1 -0
  75. package/dist/realtime/messages/index.d.ts +3 -0
  76. package/dist/realtime/messages/index.js +20 -0
  77. package/dist/realtime/messages/index.js.map +1 -0
  78. package/dist/realtime/messages/message-sync.message.d.ts +222 -0
  79. package/dist/realtime/messages/message-sync.message.js +43 -0
  80. package/dist/realtime/messages/message-sync.message.js.map +1 -0
  81. package/dist/realtime/messages/realtime-sub.direct.data.d.ts +11 -0
  82. package/dist/realtime/messages/realtime-sub.direct.data.js +3 -0
  83. package/dist/realtime/messages/realtime-sub.direct.data.js.map +1 -0
  84. package/dist/realtime/messages/thread-update.message.d.ts +68 -0
  85. package/dist/realtime/messages/thread-update.message.js +3 -0
  86. package/dist/realtime/messages/thread-update.message.js.map +1 -0
  87. package/dist/realtime/mixins/index.d.ts +3 -0
  88. package/dist/realtime/mixins/index.js +20 -0
  89. package/dist/realtime/mixins/index.js.map +1 -0
  90. package/dist/realtime/mixins/message-sync.mixin.d.ts +8 -0
  91. package/dist/realtime/mixins/message-sync.mixin.js +596 -0
  92. package/dist/realtime/mixins/message-sync.mixin.js.map +1 -0
  93. package/dist/realtime/mixins/mixin.d.ts +19 -0
  94. package/dist/realtime/mixins/mixin.js +41 -0
  95. package/dist/realtime/mixins/mixin.js.map +1 -0
  96. package/dist/realtime/mixins/presence-typing.mixin.js +33 -0
  97. package/dist/realtime/mixins/realtime-sub.mixin.d.ts +8 -0
  98. package/dist/realtime/mixins/realtime-sub.mixin.js +181 -0
  99. package/dist/realtime/mixins/realtime-sub.mixin.js.map +1 -0
  100. package/dist/realtime/parsers/graphql-parser.js +43 -0
  101. package/dist/realtime/parsers/graphql.parser.d.ts +15 -0
  102. package/dist/realtime/parsers/graphql.parser.js +22 -0
  103. package/dist/realtime/parsers/graphql.parser.js.map +1 -0
  104. package/dist/realtime/parsers/index.d.ts +6 -0
  105. package/dist/realtime/parsers/index.js +23 -0
  106. package/dist/realtime/parsers/index.js.map +1 -0
  107. package/dist/realtime/parsers/iris-parser.js +43 -0
  108. package/dist/realtime/parsers/iris.parser.d.ts +17 -0
  109. package/dist/realtime/parsers/iris.parser.js +10 -0
  110. package/dist/realtime/parsers/iris.parser.js.map +1 -0
  111. package/dist/realtime/parsers/json-parser.js +43 -0
  112. package/dist/realtime/parsers/json.parser.d.ts +6 -0
  113. package/dist/realtime/parsers/json.parser.js +10 -0
  114. package/dist/realtime/parsers/json.parser.js.map +1 -0
  115. package/dist/realtime/parsers/parser.d.ts +9 -0
  116. package/dist/realtime/parsers/parser.js +3 -0
  117. package/dist/realtime/parsers/parser.js.map +1 -0
  118. package/dist/realtime/parsers/region-hint-parser.js +43 -0
  119. package/dist/realtime/parsers/region-hint.parser.d.ts +12 -0
  120. package/dist/realtime/parsers/region-hint.parser.js +15 -0
  121. package/dist/realtime/parsers/region-hint.parser.js.map +1 -0
  122. package/dist/realtime/parsers/skywalker-parser.js +43 -0
  123. package/dist/realtime/parsers/skywalker.parser.d.ts +12 -0
  124. package/dist/realtime/parsers/skywalker.parser.js +15 -0
  125. package/dist/realtime/parsers/skywalker.parser.js.map +1 -0
  126. package/dist/realtime/parsers-advanced.js +158 -0
  127. package/dist/realtime/proto/common.proto +38 -0
  128. package/dist/realtime/proto/direct.proto +65 -0
  129. package/dist/realtime/proto/ig-messages.proto +83 -0
  130. package/dist/realtime/proto/iris.proto +188 -0
  131. package/dist/realtime/proto-parser.js +195 -0
  132. package/dist/realtime/protocols/iris.handshake.js +74 -0
  133. package/dist/realtime/protocols/proto-definitions.js +80 -0
  134. package/dist/realtime/protocols/skywalker.protocol.js +91 -0
  135. package/dist/realtime/realtime.client.events.js +3 -0
  136. package/dist/realtime/realtime.client.js +1915 -0
  137. package/dist/realtime/realtime.service.js +462 -0
  138. package/dist/realtime/reconnect.manager.js +88 -0
  139. package/dist/realtime/session.manager.js +121 -0
  140. package/dist/realtime/subscriptions/graphql.subscription.d.ts +47 -0
  141. package/dist/realtime/subscriptions/graphql.subscription.js +99 -0
  142. package/dist/realtime/subscriptions/graphql.subscription.js.map +1 -0
  143. package/dist/realtime/subscriptions/index.d.ts +2 -0
  144. package/dist/realtime/subscriptions/index.js +19 -0
  145. package/dist/realtime/subscriptions/index.js.map +1 -0
  146. package/dist/realtime/subscriptions/skywalker.subscription.d.ts +4 -0
  147. package/dist/realtime/subscriptions/skywalker.subscription.js +13 -0
  148. package/dist/realtime/subscriptions/skywalker.subscription.js.map +1 -0
  149. package/dist/realtime/topic-map.js +71 -0
  150. package/dist/realtime/topic.js +80 -0
  151. package/dist/repositories/account.repository.js +575 -0
  152. package/dist/repositories/bloks.repository.js +70 -0
  153. package/dist/repositories/captcha.repository.js +44 -0
  154. package/dist/repositories/challenge.repository.js +120 -0
  155. package/dist/repositories/clip.repository.js +165 -0
  156. package/dist/repositories/close-friends.repository.js +46 -0
  157. package/dist/repositories/collection.repository.js +68 -0
  158. package/dist/repositories/direct-thread.repository.js +446 -0
  159. package/dist/repositories/direct.repository.js +232 -0
  160. package/dist/repositories/explore.repository.js +70 -0
  161. package/dist/repositories/fbsearch.repository.js +140 -0
  162. package/dist/repositories/feed.repository.js +245 -0
  163. package/dist/repositories/friendship.repository.js +296 -0
  164. package/dist/repositories/fundraiser.repository.js +49 -0
  165. package/dist/repositories/hashtag.repository.js +99 -0
  166. package/dist/repositories/highlights.repository.js +121 -0
  167. package/dist/repositories/insights.repository.js +82 -0
  168. package/dist/repositories/location.repository.js +84 -0
  169. package/dist/repositories/media.repository.js +395 -0
  170. package/dist/repositories/multiple-accounts.repository.js +41 -0
  171. package/dist/repositories/news.repository.js +35 -0
  172. package/dist/repositories/note.repository.js +57 -0
  173. package/dist/repositories/notification.repository.js +79 -0
  174. package/dist/repositories/share.repository.js +35 -0
  175. package/dist/repositories/signup.repository.js +218 -0
  176. package/dist/repositories/story.repository.js +290 -0
  177. package/dist/repositories/timeline.repository.js +60 -0
  178. package/dist/repositories/totp.repository.js +139 -0
  179. package/dist/repositories/track.repository.js +53 -0
  180. package/dist/repositories/upload.repository.js +204 -0
  181. package/dist/repositories/user.repository.js +360 -0
  182. package/dist/sendmedia/index.js +27 -0
  183. package/dist/sendmedia/sendFile.js +72 -0
  184. package/dist/sendmedia/sendPhoto.js +142 -0
  185. package/dist/sendmedia/sendRavenPhoto.js +153 -0
  186. package/dist/sendmedia/sendRavenVideo.js +158 -0
  187. package/dist/sendmedia/uploadPhoto.js +107 -0
  188. package/dist/sendmedia/uploadfFile.js +130 -0
  189. package/dist/services/live.service.js +139 -0
  190. package/dist/services/search.service.js +115 -0
  191. package/dist/shared/index.js +96 -0
  192. package/dist/shared/shared.js +86 -0
  193. package/dist/thrift/index.d.ts +3 -0
  194. package/dist/thrift/index.js +20 -0
  195. package/dist/thrift/index.js.map +1 -0
  196. package/dist/thrift/thrift.d.ts +59 -0
  197. package/dist/thrift/thrift.js +101 -0
  198. package/dist/thrift/thrift.js.map +1 -0
  199. package/dist/thrift/thrift.reading.d.ts +41 -0
  200. package/dist/thrift/thrift.reading.js +327 -0
  201. package/dist/thrift/thrift.reading.js.map +1 -0
  202. package/dist/thrift/thrift.writing.d.ts +44 -0
  203. package/dist/thrift/thrift.writing.js +342 -0
  204. package/dist/thrift/thrift.writing.js.map +1 -0
  205. package/dist/types/index.js +285 -0
  206. package/dist/useMultiFileAuthState.js +1768 -0
  207. package/dist/utils/helper-1.js +1 -0
  208. package/dist/utils/helper-10.js +1 -0
  209. package/dist/utils/helper-11.js +1 -0
  210. package/dist/utils/helper-12.js +1 -0
  211. package/dist/utils/helper-13.js +1 -0
  212. package/dist/utils/helper-14.js +1 -0
  213. package/dist/utils/helper-15.js +1 -0
  214. package/dist/utils/helper-16.js +1 -0
  215. package/dist/utils/helper-17.js +1 -0
  216. package/dist/utils/helper-18.js +1 -0
  217. package/dist/utils/helper-19.js +1 -0
  218. package/dist/utils/helper-2.js +1 -0
  219. package/dist/utils/helper-20.js +1 -0
  220. package/dist/utils/helper-21.js +1 -0
  221. package/dist/utils/helper-22.js +1 -0
  222. package/dist/utils/helper-23.js +1 -0
  223. package/dist/utils/helper-24.js +1 -0
  224. package/dist/utils/helper-25.js +1 -0
  225. package/dist/utils/helper-26.js +1 -0
  226. package/dist/utils/helper-27.js +1 -0
  227. package/dist/utils/helper-28.js +1 -0
  228. package/dist/utils/helper-29.js +1 -0
  229. package/dist/utils/helper-3.js +1 -0
  230. package/dist/utils/helper-30.js +1 -0
  231. package/dist/utils/helper-4.js +1 -0
  232. package/dist/utils/helper-5.js +1 -0
  233. package/dist/utils/helper-6.js +1 -0
  234. package/dist/utils/helper-7.js +1 -0
  235. package/dist/utils/helper-8.js +1 -0
  236. package/dist/utils/helper-9.js +1 -0
  237. package/dist/utils/index.js +280 -0
  238. package/dist/utils/insta-mqtt-helper.js +128 -0
  239. package/examples/listen-to-messages.js +86 -0
  240. package/package.json +82 -0
@@ -0,0 +1,35 @@
1
+ const Repository = require('../core/repository');
2
+
3
+ class ShareRepository extends Repository {
4
+ shareInfo(code) {
5
+ let decoded;
6
+ if (Buffer.isBuffer(code)) {
7
+ decoded = code.toString('utf8').replace(/\x1d/g, '');
8
+ } else {
9
+ try {
10
+ decoded = Buffer.from(code, 'base64').toString('utf8').replace(/\x1d/g, '');
11
+ } catch {
12
+ decoded = String(code);
13
+ }
14
+ }
15
+ const parts = decoded.split(':');
16
+ return { type: parts[0], pk: parts[1] || '' };
17
+ }
18
+
19
+ shareInfoByUrl(url) {
20
+ const code = this.shareCodeFromUrl(url);
21
+ return this.shareInfo(code);
22
+ }
23
+
24
+ shareCodeFromUrl(url) {
25
+ try {
26
+ const parsed = new URL(url);
27
+ const parts = parsed.pathname.split('/').filter(p => p.length > 0);
28
+ return parts[parts.length - 1];
29
+ } catch {
30
+ return url;
31
+ }
32
+ }
33
+ }
34
+
35
+ module.exports = ShareRepository;
@@ -0,0 +1,218 @@
1
+ const Repository = require('../core/repository');
2
+
3
+ class SignupRepository extends Repository {
4
+ constructor(client) {
5
+ super(client);
6
+ this.waterfallId = this._generateUUID();
7
+ }
8
+
9
+ _generateUUID() {
10
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
11
+ const r = Math.random() * 16 | 0;
12
+ return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
13
+ });
14
+ }
15
+
16
+ async signup(options = {}) {
17
+ const {
18
+ username,
19
+ password,
20
+ email,
21
+ phoneNumber = '',
22
+ fullName = '',
23
+ year = null,
24
+ month = null,
25
+ day = null,
26
+ } = options;
27
+
28
+ await this.getSignupConfig();
29
+
30
+ const checkResult = await this.checkEmail(email);
31
+ if (!checkResult.valid) {
32
+ throw new Error(`Email not valid: ${checkResult.error_title || JSON.stringify(checkResult)}`);
33
+ }
34
+ if (!checkResult.available) {
35
+ throw new Error(`Email not available: ${checkResult.feedback_message || JSON.stringify(checkResult)}`);
36
+ }
37
+
38
+ const sendResult = await this.sendVerifyEmail(email);
39
+ if (!sendResult.email_sent) {
40
+ throw new Error(`Failed to send verification email: ${JSON.stringify(sendResult)}`);
41
+ }
42
+
43
+ if (year && month && day) {
44
+ const ageCheck = await this.checkAgeEligibility(year, month, day);
45
+ if (!ageCheck.eligible) {
46
+ throw new Error(`Not eligible based on age: ${JSON.stringify(ageCheck)}`);
47
+ }
48
+ }
49
+
50
+ return { status: 'verification_sent', email };
51
+ }
52
+
53
+ async getSignupConfig() {
54
+ const response = await this.client.request.send({
55
+ method: 'GET',
56
+ url: '/api/v1/consent/get_signup_config/',
57
+ qs: {
58
+ guid: this.client.state.uuid,
59
+ main_account_selected: false,
60
+ },
61
+ });
62
+ return response.body;
63
+ }
64
+
65
+ async checkEmail(email) {
66
+ const response = await this.client.request.send({
67
+ method: 'POST',
68
+ url: '/api/v1/users/check_email/',
69
+ form: {
70
+ android_device_id: this.client.state.deviceId,
71
+ login_nonce_map: '{}',
72
+ login_nonces: '[]',
73
+ email,
74
+ qe_id: this._generateUUID(),
75
+ waterfall_id: this.waterfallId,
76
+ },
77
+ });
78
+ return response.body;
79
+ }
80
+
81
+ async checkUsername(username) {
82
+ const response = await this.client.request.send({
83
+ method: 'POST',
84
+ url: '/api/v1/users/check_username/',
85
+ form: {
86
+ username,
87
+ _uuid: this.client.state.uuid,
88
+ },
89
+ });
90
+ return response.body;
91
+ }
92
+
93
+ async sendVerifyEmail(email) {
94
+ const response = await this.client.request.send({
95
+ method: 'POST',
96
+ url: '/api/v1/accounts/send_verify_email/',
97
+ form: {
98
+ phone_id: this.client.state.phoneId,
99
+ device_id: this.client.state.deviceId,
100
+ email,
101
+ waterfall_id: this.waterfallId,
102
+ auto_confirm_only: 'false',
103
+ },
104
+ });
105
+ return response.body;
106
+ }
107
+
108
+ async checkConfirmationCode(email, code) {
109
+ const response = await this.client.request.send({
110
+ method: 'POST',
111
+ url: '/api/v1/accounts/check_confirmation_code/',
112
+ form: {
113
+ code,
114
+ device_id: this.client.state.deviceId,
115
+ email,
116
+ waterfall_id: this.waterfallId,
117
+ },
118
+ });
119
+ return response.body;
120
+ }
121
+
122
+ async checkAgeEligibility(year, month, day) {
123
+ const response = await this.client.request.send({
124
+ method: 'POST',
125
+ url: '/api/v1/consent/check_age_eligibility/',
126
+ form: {
127
+ _uuid: this.client.state.uuid,
128
+ day: String(day),
129
+ month: String(month),
130
+ year: String(year),
131
+ },
132
+ });
133
+ return response.body;
134
+ }
135
+
136
+ async accountsCreate(options = {}) {
137
+ const {
138
+ username,
139
+ password,
140
+ email,
141
+ signupCode,
142
+ fullName = '',
143
+ year = null,
144
+ month = null,
145
+ day = null,
146
+ } = options;
147
+
148
+ const { encrypted, time } = this.client.account.encryptPassword(password);
149
+
150
+ const data = {
151
+ enc_password: `#PWD_INSTAGRAM:4:${time}:${encrypted}`,
152
+ phone_id: this.client.state.phoneId,
153
+ username,
154
+ first_name: fullName,
155
+ day: day ? String(day) : '',
156
+ month: month ? String(month) : '',
157
+ year: year ? String(year) : '',
158
+ device_id: this.client.state.deviceId,
159
+ email,
160
+ signup_code: signupCode || '',
161
+ waterfall_id: this.waterfallId,
162
+ _uuid: this.client.state.uuid,
163
+ force_sign_up_code: '',
164
+ qs_stamp: '',
165
+ has_sms_consent: 'true',
166
+ };
167
+
168
+ const response = await this.client.request.send({
169
+ method: 'POST',
170
+ url: '/api/v1/accounts/create/',
171
+ form: this.client.request.sign(data),
172
+ });
173
+ return response.body;
174
+ }
175
+
176
+ async sendSignupSmsCode(phoneNumber) {
177
+ const response = await this.client.request.send({
178
+ method: 'POST',
179
+ url: '/api/v1/accounts/send_signup_sms_code/',
180
+ form: this.client.request.sign({
181
+ phone_id: this.client.state.phoneId,
182
+ phone_number: phoneNumber,
183
+ waterfall_id: this.waterfallId,
184
+ has_whatsapp_installed: '0',
185
+ }),
186
+ });
187
+ return response.body;
188
+ }
189
+
190
+ async validateSignupSmsCode(phoneNumber, code) {
191
+ const response = await this.client.request.send({
192
+ method: 'POST',
193
+ url: '/api/v1/accounts/validate_signup_sms_code/',
194
+ form: this.client.request.sign({
195
+ phone_id: this.client.state.phoneId,
196
+ phone_number: phoneNumber,
197
+ verification_code: code,
198
+ waterfall_id: this.waterfallId,
199
+ }),
200
+ });
201
+ return response.body;
202
+ }
203
+
204
+ async getSuggestedUsernames(name, email) {
205
+ const response = await this.client.request.send({
206
+ method: 'POST',
207
+ url: '/api/v1/accounts/username_suggestions/',
208
+ form: {
209
+ name: name || '',
210
+ email: email || '',
211
+ waterfall_id: this.waterfallId,
212
+ },
213
+ });
214
+ return response.body;
215
+ }
216
+ }
217
+
218
+ module.exports = SignupRepository;
@@ -0,0 +1,290 @@
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
+ const response = await this.client.request.send({
8
+ url: `/api/v1/media/${storyId}/story_react/`,
9
+ method: 'POST',
10
+ form: this.client.request.sign({
11
+ _uid: this.client.state.cookieUserId,
12
+ _uuid: this.client.state.uuid,
13
+ reaction_type: 'like',
14
+ emoji: reaction || '\u2764\uFE0F',
15
+ }),
16
+ });
17
+ return response.body;
18
+ }
19
+
20
+ async getFeed() {
21
+ const response = await this.client.request.send({
22
+ method: 'POST',
23
+ url: '/api/v1/feed/reels_tray/',
24
+ form: this.client.request.sign({
25
+ supported_capabilities_new: JSON.stringify(this.client.state.constants.SUPPORTED_CAPABILITIES),
26
+ reason: 'pull_to_refresh',
27
+ _uuid: this.client.state.uuid,
28
+ }),
29
+ });
30
+ return response.body;
31
+ }
32
+
33
+ async getUser(userId) {
34
+ const response = await this.client.request.send({
35
+ method: 'GET',
36
+ url: `/api/v1/feed/user/${userId}/reel_media/`,
37
+ });
38
+ return response.body;
39
+ }
40
+
41
+ async getUserStories(userId) {
42
+ return this.getUser(userId);
43
+ }
44
+
45
+ async upload(options) {
46
+ const { imagePath, caption, mentions, links, hashtags, stickers } = options;
47
+ const imageBuffer = fs.readFileSync(imagePath);
48
+ const uploadId = Date.now();
49
+ const uploadResult = await this.client.upload.photo({
50
+ file: imageBuffer,
51
+ uploadId,
52
+ });
53
+
54
+ return this.configureStory({
55
+ uploadId: uploadResult.upload_id,
56
+ caption,
57
+ mentions,
58
+ links,
59
+ hashtags,
60
+ stickers,
61
+ });
62
+ }
63
+
64
+ async uploadVideo(options) {
65
+ const { videoPath, caption, mentions, links, hashtags, stickers } = options;
66
+ const videoBuffer = fs.readFileSync(videoPath);
67
+ const uploadId = Date.now();
68
+ const uploadResult = await this.client.upload.video({
69
+ video: videoBuffer,
70
+ uploadId,
71
+ duration_ms: options.duration_ms || 15000,
72
+ width: options.width || 720,
73
+ height: options.height || 1280,
74
+ });
75
+
76
+ return this.configureStoryVideo({
77
+ uploadId: uploadResult.upload_id,
78
+ caption,
79
+ mentions,
80
+ links,
81
+ hashtags,
82
+ stickers,
83
+ length: options.duration_ms || 15000,
84
+ });
85
+ }
86
+
87
+ async configureStory(options = {}) {
88
+ const { uploadId, caption, mentions, links, hashtags, stickers } = options;
89
+ const data = {
90
+ upload_id: uploadId,
91
+ source_type: '4',
92
+ configure_mode: '1',
93
+ caption: caption || '',
94
+ _uid: this.client.state.cookieUserId,
95
+ _uuid: this.client.state.uuid,
96
+ };
97
+
98
+ if (mentions && mentions.length > 0) {
99
+ data.reel_mentions = JSON.stringify(mentions);
100
+ }
101
+ if (links && links.length > 0) {
102
+ data.story_cta = JSON.stringify(links.map(l => ({
103
+ links: [{ webUri: l.url || l, linkType: 1 }],
104
+ })));
105
+ }
106
+ if (hashtags && hashtags.length > 0) {
107
+ data.story_hashtags = JSON.stringify(hashtags);
108
+ }
109
+ if (stickers && stickers.length > 0) {
110
+ data.story_sticker_ids = JSON.stringify(stickers.map(s => s.id || s));
111
+ }
112
+
113
+ const response = await this.client.request.send({
114
+ url: '/api/v1/media/configure_to_story/',
115
+ method: 'POST',
116
+ form: this.client.request.sign(data),
117
+ });
118
+ return response.body;
119
+ }
120
+
121
+ async configureStoryVideo(options = {}) {
122
+ const { uploadId, caption, mentions, links, hashtags, stickers, length } = options;
123
+ const data = {
124
+ upload_id: uploadId,
125
+ source_type: '4',
126
+ configure_mode: '1',
127
+ caption: caption || '',
128
+ _uid: this.client.state.cookieUserId,
129
+ _uuid: this.client.state.uuid,
130
+ video_result: 'deprecated',
131
+ length: length || 0,
132
+ clips: JSON.stringify([{ length: length || 0, source_type: '4' }]),
133
+ poster_frame_index: '0',
134
+ audio_muted: '0',
135
+ };
136
+
137
+ if (mentions && mentions.length > 0) {
138
+ data.reel_mentions = JSON.stringify(mentions);
139
+ }
140
+ if (links && links.length > 0) {
141
+ data.story_cta = JSON.stringify(links.map(l => ({
142
+ links: [{ webUri: l.url || l, linkType: 1 }],
143
+ })));
144
+ }
145
+ if (hashtags && hashtags.length > 0) {
146
+ data.story_hashtags = JSON.stringify(hashtags);
147
+ }
148
+ if (stickers && stickers.length > 0) {
149
+ data.story_sticker_ids = JSON.stringify(stickers.map(s => s.id || s));
150
+ }
151
+
152
+ const response = await this.client.request.send({
153
+ url: '/api/v1/media/configure_to_story/',
154
+ method: 'POST',
155
+ form: this.client.request.sign(data),
156
+ });
157
+ return response.body;
158
+ }
159
+
160
+ async seen(input, sourceId = null) {
161
+ let items = [];
162
+ if (Array.isArray(input)) {
163
+ items = input;
164
+ } else {
165
+ items = Object.values(input).reduce((acc, reel) => acc.concat(reel.items || []), []);
166
+ }
167
+
168
+ const reels = {};
169
+ const maxSeenAt = Math.floor(Date.now() / 1000);
170
+ let seenAt = maxSeenAt - items.length;
171
+
172
+ for (const item of items) {
173
+ const itemTakenAt = item.taken_at;
174
+ if (seenAt < itemTakenAt) seenAt = itemTakenAt + 1;
175
+ if (seenAt > maxSeenAt) seenAt = maxSeenAt;
176
+ const itemSourceId = sourceId === null ? item.user.pk : sourceId;
177
+ const reelId = `${item.id}_${itemSourceId}`;
178
+ reels[reelId] = [`${itemTakenAt}_${seenAt}`];
179
+ seenAt += 1;
180
+ }
181
+
182
+ return this.client.media.seen(reels);
183
+ }
184
+
185
+ async getHighlights(userId) {
186
+ const response = await this.client.request.send({
187
+ method: 'GET',
188
+ url: `/api/v1/highlights/${userId}/highlights_tray/`,
189
+ });
190
+ return response.body;
191
+ }
192
+
193
+ async getHighlight(highlightId) {
194
+ const ids = Array.isArray(highlightId) ? highlightId : [highlightId];
195
+ const response = await this.client.request.send({
196
+ method: 'POST',
197
+ url: '/api/v1/feed/reels_media/',
198
+ form: this.client.request.sign({
199
+ user_ids: ids,
200
+ _uuid: this.client.state.uuid,
201
+ }),
202
+ });
203
+ return response.body;
204
+ }
205
+
206
+ async getHighlightById(highlightId) {
207
+ return this.getHighlight(highlightId);
208
+ }
209
+
210
+ async viewers(storyId) {
211
+ const response = await this.client.request.send({
212
+ method: 'GET',
213
+ url: `/api/v1/media/${storyId}/list_reel_media_viewer/`,
214
+ });
215
+ return response.body;
216
+ }
217
+
218
+ async deleteStory(storyId) {
219
+ return this.client.media.delete(storyId, 'STORY');
220
+ }
221
+
222
+ async downloadByUrl(url) {
223
+ const axios = require('axios');
224
+ const response = await axios.get(url, { responseType: 'arraybuffer' });
225
+ return Buffer.from(response.data);
226
+ }
227
+
228
+ async download(storyPk) {
229
+ const result = await this.client.media.info(storyPk);
230
+ const items = result.items || [result];
231
+ const item = items[0] || result;
232
+ if (item.video_versions && item.video_versions.length > 0) {
233
+ return this.downloadByUrl(item.video_versions[0].url);
234
+ }
235
+ const candidates = item.image_versions2?.candidates || [];
236
+ if (candidates.length > 0) {
237
+ return this.downloadByUrl(candidates[0].url);
238
+ }
239
+ throw new Error('No media URL found for story');
240
+ }
241
+
242
+ async createHighlight(options = {}) {
243
+ const { title, coverMediaId, mediaIds = [] } = options;
244
+ const response = await this.client.request.send({
245
+ method: 'POST',
246
+ url: '/api/v1/highlights/create_reel/',
247
+ form: this.client.request.sign({
248
+ _uuid: this.client.state.uuid,
249
+ _uid: this.client.state.cookieUserId,
250
+ title: title || '',
251
+ cover: JSON.stringify({ media_id: coverMediaId }),
252
+ media_ids: JSON.stringify(mediaIds),
253
+ }),
254
+ });
255
+ return response.body;
256
+ }
257
+
258
+ async editHighlight(highlightId, options = {}) {
259
+ const { title, coverMediaId, addedMediaIds = [], removedMediaIds = [] } = options;
260
+ const data = {
261
+ _uuid: this.client.state.uuid,
262
+ _uid: this.client.state.cookieUserId,
263
+ };
264
+ if (title) data.title = title;
265
+ if (coverMediaId) data.cover = JSON.stringify({ media_id: coverMediaId });
266
+ if (addedMediaIds.length > 0) data.added_media_ids = JSON.stringify(addedMediaIds);
267
+ if (removedMediaIds.length > 0) data.removed_media_ids = JSON.stringify(removedMediaIds);
268
+
269
+ const response = await this.client.request.send({
270
+ method: 'POST',
271
+ url: `/api/v1/highlights/${highlightId}/edit_reel/`,
272
+ form: this.client.request.sign(data),
273
+ });
274
+ return response.body;
275
+ }
276
+
277
+ async deleteHighlight(highlightId) {
278
+ const response = await this.client.request.send({
279
+ method: 'POST',
280
+ url: `/api/v1/highlights/${highlightId}/delete_reel/`,
281
+ form: this.client.request.sign({
282
+ _uuid: this.client.state.uuid,
283
+ _uid: this.client.state.cookieUserId,
284
+ }),
285
+ });
286
+ return response.body;
287
+ }
288
+ }
289
+
290
+ module.exports = StoryRepository;
@@ -0,0 +1,60 @@
1
+ const Repository = require('../core/repository');
2
+
3
+ class TimelineRepository extends Repository {
4
+ async reels(amount = 10, lastMediaPk = 0) {
5
+ return this._reelsTimelineMedia('clips/connected/', amount, lastMediaPk);
6
+ }
7
+
8
+ async exploreReels(amount = 10, lastMediaPk = 0) {
9
+ return this._reelsTimelineMedia('clips/discover/', amount, lastMediaPk);
10
+ }
11
+
12
+ async _reelsTimelineMedia(endpoint, amount = 10, lastMediaPk = 0) {
13
+ const totalItems = [];
14
+ let nextMaxId = '';
15
+ while (totalItems.length < amount) {
16
+ try {
17
+ const response = await this.client.request.send({
18
+ method: 'POST',
19
+ url: `/api/v1/${endpoint}`,
20
+ form: { max_id: nextMaxId },
21
+ });
22
+ const body = response.body;
23
+ for (const item of (body.items || [])) {
24
+ const media = item.media || item;
25
+ if (lastMediaPk && String(media.pk) === String(lastMediaPk)) {
26
+ return totalItems;
27
+ }
28
+ totalItems.push(media);
29
+ }
30
+ const pagingInfo = body.paging_info || {};
31
+ if (!pagingInfo.more_available) return totalItems;
32
+ nextMaxId = pagingInfo.max_id || '';
33
+ } catch (e) {
34
+ return totalItems;
35
+ }
36
+ }
37
+ return totalItems.slice(0, amount);
38
+ }
39
+
40
+ async getFeed(maxId = '', options = {}) {
41
+ const response = await this.client.request.send({
42
+ method: 'POST',
43
+ url: '/api/v1/feed/timeline/',
44
+ form: this.client.request.sign({
45
+ _uuid: this.client.state.uuid,
46
+ is_prefetch: '0',
47
+ feed_view_info: '[]',
48
+ seen_posts: '',
49
+ phone_id: this.client.state.phoneId,
50
+ battery_level: String(Math.floor(Math.random() * 50) + 50),
51
+ timezone_offset: String(this.client.state.timezoneOffset),
52
+ max_id: maxId,
53
+ ...options,
54
+ }),
55
+ });
56
+ return response.body;
57
+ }
58
+ }
59
+
60
+ module.exports = TimelineRepository;