emusks 2.0.4 → 2.0.5
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/build/graphql.js +5 -13
- package/package.json +1 -1
- package/src/graphql.js +34 -12
- package/src/helpers/account.js +267 -269
- package/src/helpers/bookmarks.js +101 -103
- package/src/helpers/communities.js +236 -238
- package/src/helpers/dms.js +129 -131
- package/src/helpers/index.js +50 -31
- package/src/helpers/lists.js +222 -224
- package/src/helpers/media.js +137 -139
- package/src/helpers/notifications.js +42 -44
- package/src/helpers/search.js +117 -119
- package/src/helpers/spaces.js +47 -49
- package/src/helpers/syndication.js +23 -25
- package/src/helpers/timelines.js +76 -78
- package/src/helpers/topics.js +87 -89
- package/src/helpers/trends.js +74 -76
- package/src/helpers/tweets.js +302 -304
- package/src/helpers/users.js +287 -289
- package/src/index.js +23 -19
- package/src/static/graphql.js +1 -1
package/src/helpers/media.js
CHANGED
|
@@ -65,20 +65,20 @@ function checkMediaSize(category, size) {
|
|
|
65
65
|
size > MAX_IMAGE_SIZE
|
|
66
66
|
)
|
|
67
67
|
throw new Error(
|
|
68
|
-
`cannot upload ${fmt(size)} image
|
|
68
|
+
`cannot upload ${fmt(size)} image \u2014 max is ${fmt(MAX_IMAGE_SIZE)}`,
|
|
69
69
|
);
|
|
70
70
|
if (category.includes("gif") && size > MAX_GIF_SIZE)
|
|
71
71
|
throw new Error(
|
|
72
|
-
`cannot upload ${fmt(size)} gif
|
|
72
|
+
`cannot upload ${fmt(size)} gif \u2014 max is ${fmt(MAX_GIF_SIZE)}`,
|
|
73
73
|
);
|
|
74
74
|
if (category.includes("video") && size > MAX_VIDEO_SIZE)
|
|
75
75
|
throw new Error(
|
|
76
|
-
`cannot upload ${fmt(size)} video
|
|
76
|
+
`cannot upload ${fmt(size)} video \u2014 max is ${fmt(MAX_VIDEO_SIZE)}`,
|
|
77
77
|
);
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
async function makeUploadRequest(
|
|
81
|
-
|
|
81
|
+
instance,
|
|
82
82
|
method,
|
|
83
83
|
params,
|
|
84
84
|
body,
|
|
@@ -90,22 +90,22 @@ async function makeUploadRequest(
|
|
|
90
90
|
const headers = {
|
|
91
91
|
accept: "*/*",
|
|
92
92
|
"accept-language": "en-US,en;q=0.9",
|
|
93
|
-
authorization: `Bearer ${
|
|
94
|
-
"x-csrf-token":
|
|
93
|
+
authorization: `Bearer ${instance.auth.client.bearer}`,
|
|
94
|
+
"x-csrf-token": instance.auth.csrfToken,
|
|
95
95
|
"x-twitter-active-user": "yes",
|
|
96
96
|
"x-twitter-auth-type": "OAuth2Session",
|
|
97
97
|
"x-twitter-client-language": "en",
|
|
98
98
|
priority: "u=1, i",
|
|
99
|
-
"sec-ch-ua": '
|
|
99
|
+
"sec-ch-ua": '\u0022Not(A:Brand\u0022;v=\u00228\u0022, \u0022Chromium\u0022;v=\u0022144\u0022',
|
|
100
100
|
"sec-ch-ua-mobile": "?0",
|
|
101
|
-
"sec-ch-ua-platform": '
|
|
101
|
+
"sec-ch-ua-platform": '\u0022macOS\u0022',
|
|
102
102
|
"sec-fetch-dest": "empty",
|
|
103
103
|
"sec-fetch-mode": "cors",
|
|
104
104
|
"sec-fetch-site": "same-site",
|
|
105
105
|
"sec-gpc": "1",
|
|
106
106
|
cookie:
|
|
107
|
-
|
|
108
|
-
(
|
|
107
|
+
instance.auth.client.headers.cookie +
|
|
108
|
+
(instance.elevatedCookies ? `; ${instance.elevatedCookies}` : ""),
|
|
109
109
|
...extraHeaders,
|
|
110
110
|
};
|
|
111
111
|
|
|
@@ -114,161 +114,159 @@ async function makeUploadRequest(
|
|
|
114
114
|
{
|
|
115
115
|
headers,
|
|
116
116
|
userAgent:
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
ja3:
|
|
120
|
-
ja4r:
|
|
117
|
+
instance.auth.client.fingerprints?.userAgent ||
|
|
118
|
+
instance.auth.client.fingerprints?.["user-agent"],
|
|
119
|
+
ja3: instance.auth.client.fingerprints?.ja3,
|
|
120
|
+
ja4r: instance.auth.client.fingerprints?.ja4r,
|
|
121
121
|
body: body || undefined,
|
|
122
|
-
proxy:
|
|
122
|
+
proxy: instance.proxy || undefined,
|
|
123
123
|
referrer: "https://x.com/",
|
|
124
124
|
},
|
|
125
125
|
method,
|
|
126
126
|
);
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
-
export
|
|
130
|
-
|
|
131
|
-
if (!client.auth) throw new Error("you must be logged in to upload media");
|
|
129
|
+
export async function create(source, opts = {}) {
|
|
130
|
+
if (!this.auth) throw new Error("you must be logged in to upload media");
|
|
132
131
|
|
|
133
|
-
|
|
134
|
-
|
|
132
|
+
let buf;
|
|
133
|
+
let mediaType = opts.mediaType;
|
|
135
134
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
135
|
+
if (typeof source === "string") {
|
|
136
|
+
buf = await readFile(source);
|
|
137
|
+
if (!mediaType) mediaType = MIME_BY_EXT[extname(source).toLowerCase()];
|
|
138
|
+
} else if (typeof Blob !== "undefined" && source instanceof Blob) {
|
|
139
|
+
buf = Buffer.from(await source.arrayBuffer());
|
|
140
|
+
if (!mediaType) mediaType = source.type || undefined;
|
|
141
|
+
} else if (
|
|
142
|
+
source instanceof ArrayBuffer ||
|
|
143
|
+
source instanceof SharedArrayBuffer
|
|
144
|
+
) {
|
|
145
|
+
buf = Buffer.from(source);
|
|
146
|
+
} else if (Buffer.isBuffer(source) || source instanceof Uint8Array) {
|
|
147
|
+
buf = Buffer.from(source);
|
|
148
|
+
} else {
|
|
149
|
+
throw new Error(
|
|
150
|
+
"source must be a file path (string), Buffer, Uint8Array, ArrayBuffer, or Blob",
|
|
151
|
+
);
|
|
152
|
+
}
|
|
154
153
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
154
|
+
if (!mediaType) mediaType = detectMediaType(buf);
|
|
155
|
+
if (!mediaType)
|
|
156
|
+
throw new Error(
|
|
157
|
+
"could not detect media type \u2014 pass opts.mediaType (e.g. 'image/png')",
|
|
158
|
+
);
|
|
160
159
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
160
|
+
const totalBytes = buf.length;
|
|
161
|
+
const uploadType = opts.type === "dm" ? "dm" : "tweet";
|
|
162
|
+
const category = getMediaCategory(mediaType, uploadType);
|
|
163
|
+
checkMediaSize(category, totalBytes);
|
|
165
164
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
165
|
+
const initRes = await makeUploadRequest(this, "post", {
|
|
166
|
+
command: "INIT",
|
|
167
|
+
media_type: mediaType,
|
|
168
|
+
total_bytes: totalBytes.toString(),
|
|
169
|
+
media_category: category,
|
|
170
|
+
});
|
|
172
171
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
172
|
+
const initData = await initRes.json();
|
|
173
|
+
if (!initData?.media_id_string) {
|
|
174
|
+
throw new Error(`upload INIT failed: ${JSON.stringify(initData)}`);
|
|
175
|
+
}
|
|
176
|
+
const mediaId = initData.media_id_string;
|
|
178
177
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
178
|
+
let segmentIndex = 0;
|
|
179
|
+
for (let offset = 0; offset < totalBytes; offset += CHUNK_SIZE) {
|
|
180
|
+
const chunk = buf.slice(
|
|
181
|
+
offset,
|
|
182
|
+
Math.min(offset + CHUNK_SIZE, totalBytes),
|
|
183
|
+
);
|
|
184
|
+
const base64 = chunk.toString("base64");
|
|
186
185
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
186
|
+
await makeUploadRequest(
|
|
187
|
+
this,
|
|
188
|
+
"post",
|
|
189
|
+
{
|
|
190
|
+
command: "APPEND",
|
|
191
|
+
media_id: mediaId,
|
|
192
|
+
segment_index: segmentIndex.toString(),
|
|
193
|
+
},
|
|
194
|
+
`media_data=${encodeURIComponent(base64)}`,
|
|
195
|
+
{ "content-type": "application/x-www-form-urlencoded" },
|
|
196
|
+
);
|
|
197
|
+
segmentIndex++;
|
|
198
|
+
}
|
|
200
199
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
200
|
+
const finalizeRes = await makeUploadRequest(this, "post", {
|
|
201
|
+
command: "FINALIZE",
|
|
202
|
+
media_id: mediaId,
|
|
203
|
+
allow_async: "true",
|
|
204
|
+
});
|
|
206
205
|
|
|
207
|
-
|
|
208
|
-
|
|
206
|
+
const finalizeData = await finalizeRes.json();
|
|
207
|
+
if (finalizeData?.error) {
|
|
208
|
+
throw new Error(
|
|
209
|
+
`upload FINALIZE failed: ${JSON.stringify(finalizeData)}`,
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
let processingInfo = finalizeData?.processing_info;
|
|
214
|
+
while (processingInfo) {
|
|
215
|
+
if (processingInfo.error) {
|
|
209
216
|
throw new Error(
|
|
210
|
-
`
|
|
217
|
+
`media processing error: ${JSON.stringify(processingInfo.error)}`,
|
|
211
218
|
);
|
|
212
219
|
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
`media processing error: ${JSON.stringify(processingInfo.error)}`,
|
|
219
|
-
);
|
|
220
|
-
}
|
|
221
|
-
if (processingInfo.state === "succeeded") break;
|
|
222
|
-
if (processingInfo.state === "failed") {
|
|
223
|
-
throw new Error(
|
|
224
|
-
`media processing failed: ${JSON.stringify(processingInfo)}`,
|
|
225
|
-
);
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
const wait = (processingInfo.check_after_secs || 2) * 1000;
|
|
229
|
-
await new Promise((r) => setTimeout(r, wait));
|
|
230
|
-
|
|
231
|
-
const statusRes = await makeUploadRequest(client, "get", {
|
|
232
|
-
command: "STATUS",
|
|
233
|
-
media_id: mediaId,
|
|
234
|
-
});
|
|
235
|
-
const statusData = await statusRes.json();
|
|
236
|
-
processingInfo = statusData?.processing_info;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
if (opts.alt_text) {
|
|
240
|
-
await client.v1_1("media/metadata/create", {
|
|
241
|
-
body: JSON.stringify({
|
|
242
|
-
media_id: mediaId,
|
|
243
|
-
alt_text: { text: opts.alt_text },
|
|
244
|
-
}),
|
|
245
|
-
});
|
|
220
|
+
if (processingInfo.state === "succeeded") break;
|
|
221
|
+
if (processingInfo.state === "failed") {
|
|
222
|
+
throw new Error(
|
|
223
|
+
`media processing failed: ${JSON.stringify(processingInfo)}`,
|
|
224
|
+
);
|
|
246
225
|
}
|
|
247
226
|
|
|
248
|
-
|
|
249
|
-
|
|
227
|
+
const wait = (processingInfo.check_after_secs || 2) * 1000;
|
|
228
|
+
await new Promise((r) => setTimeout(r, wait));
|
|
250
229
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
media_id: mediaId,
|
|
255
|
-
alt_text: { text: altText },
|
|
256
|
-
...opts,
|
|
257
|
-
}),
|
|
230
|
+
const statusRes = await makeUploadRequest(this, "get", {
|
|
231
|
+
command: "STATUS",
|
|
232
|
+
media_id: mediaId,
|
|
258
233
|
});
|
|
259
|
-
|
|
260
|
-
|
|
234
|
+
const statusData = await statusRes.json();
|
|
235
|
+
processingInfo = statusData?.processing_info;
|
|
236
|
+
}
|
|
261
237
|
|
|
262
|
-
|
|
263
|
-
|
|
238
|
+
if (opts.alt_text) {
|
|
239
|
+
await this.v1_1("media/metadata/create", {
|
|
264
240
|
body: JSON.stringify({
|
|
265
241
|
media_id: mediaId,
|
|
266
|
-
|
|
267
|
-
subtitle_info: {
|
|
268
|
-
subtitles: Array.isArray(subtitles) ? subtitles : [subtitles],
|
|
269
|
-
},
|
|
242
|
+
alt_text: { text: opts.alt_text },
|
|
270
243
|
}),
|
|
271
244
|
});
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
return { media_id: mediaId, ...finalizeData };
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
export async function createMetadata(mediaId, altText, opts = {}) {
|
|
251
|
+
const res = await this.v1_1("media/metadata/create", {
|
|
252
|
+
body: JSON.stringify({
|
|
253
|
+
media_id: mediaId,
|
|
254
|
+
alt_text: { text: altText },
|
|
255
|
+
...opts,
|
|
256
|
+
}),
|
|
257
|
+
});
|
|
258
|
+
return await res.json();
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
export async function createSubtitles(mediaId, subtitles) {
|
|
262
|
+
const res = await this.v1_1("media/subtitles/create", {
|
|
263
|
+
body: JSON.stringify({
|
|
264
|
+
media_id: mediaId,
|
|
265
|
+
media_category: "tweet_video",
|
|
266
|
+
subtitle_info: {
|
|
267
|
+
subtitles: Array.isArray(subtitles) ? subtitles : [subtitles],
|
|
268
|
+
},
|
|
269
|
+
}),
|
|
270
|
+
});
|
|
271
|
+
return await res.json();
|
|
272
|
+
}
|
|
@@ -1,49 +1,47 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
},
|
|
1
|
+
export async function timeline(opts = {}) {
|
|
2
|
+
return await this.graphql("NotificationsTimeline", {
|
|
3
|
+
variables: {
|
|
4
|
+
count: opts.count || 20,
|
|
5
|
+
cursor: opts.cursor,
|
|
6
|
+
includePromotedContent: false,
|
|
7
|
+
...opts.variables,
|
|
8
|
+
},
|
|
9
|
+
fieldToggles: {
|
|
10
|
+
withArticlePlainText: false,
|
|
11
|
+
withArticleRichContentState: false,
|
|
12
|
+
withAuxiliaryUserLabels: false,
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
}
|
|
17
16
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
export async function enableWebNotifications() {
|
|
18
|
+
return await this.graphql("EnableLoggedOutWebNotifications", {
|
|
19
|
+
body: { variables: {} },
|
|
20
|
+
});
|
|
21
|
+
}
|
|
23
22
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
23
|
+
export async function saveSettings(params = {}) {
|
|
24
|
+
const res = await this.v1_1("notifications/settings/save", {
|
|
25
|
+
body: JSON.stringify(params),
|
|
26
|
+
});
|
|
27
|
+
return await res.json();
|
|
28
|
+
}
|
|
30
29
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
30
|
+
export async function loginSettings(params = {}) {
|
|
31
|
+
const res = await this.v1_1("notifications/settings/login", {
|
|
32
|
+
body: JSON.stringify(params),
|
|
33
|
+
});
|
|
34
|
+
return await res.json();
|
|
35
|
+
}
|
|
37
36
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
37
|
+
export async function checkin(params = {}) {
|
|
38
|
+
const res = await this.v1_1("notifications/settings/checkin", {
|
|
39
|
+
body: JSON.stringify(params),
|
|
40
|
+
});
|
|
41
|
+
return await res.json();
|
|
42
|
+
}
|
|
44
43
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
});
|
|
44
|
+
export async function badge(params = {}) {
|
|
45
|
+
const res = await this.v2("badge_count/badge_count", { params });
|
|
46
|
+
return await res.json();
|
|
47
|
+
}
|