emusks 2.3.1 → 2.3.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  <img src="https://emusks.tiago.zip/icon.svg" width="120">
2
2
  <h1>emusks: Reverse-engineered Twitter API client</h1>
3
3
 
4
- Log in and interact with the unofficial X API using any client identity - web, Android, iOS, or TweetDeck. Covers tweets, users, DMs, communities, spaces, articles, Community Notes, delegate/act-as, Grok (X's built-in AI), and XChat (X's end-to-end encrypted chat): send encrypted DMs in one call.
4
+ Log in and interact with the unofficial X API using any client identity - web, Android, iOS, or TweetDeck. Covers tweets, drafts, users, DMs, communities, spaces, articles, Community Notes, the immersive video feed, delegate/act-as, Grok (X's built-in AI), and XChat (X's end-to-end encrypted chat): send encrypted DMs in one call.
5
5
 
6
6
  officially dmca'd by twitter™ 🏆 • includes a few leaked ads bearers
7
7
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "emusks",
3
- "version": "2.3.1",
3
+ "version": "2.3.2",
4
4
  "description": "Reverse-engineered Twitter API client. Log in and interact with the unofficial X API using any client identity - web, Android, iOS, or TweetDeck",
5
5
  "keywords": [
6
6
  "client",
@@ -267,3 +267,8 @@ export async function disableAccountLabel() {
267
267
  body: { variables: {} },
268
268
  });
269
269
  }
270
+
271
+ export async function supportedLanguages() {
272
+ const res = await this.graphql("SupportedLanguages", { variables: {} });
273
+ return res?.data?.supported_languages?.supported_languages ?? res?.data ?? res;
274
+ }
@@ -0,0 +1,38 @@
1
+ function buildPostTweetRequest(text, opts = {}) {
2
+ return {
3
+ status: text ?? "",
4
+ ...(opts.mediaIds ? { media_ids: opts.mediaIds } : {}),
5
+ ...(opts.replyTo ? { in_reply_to_status_id: opts.replyTo } : {}),
6
+ auto_populate_reply_metadata: true,
7
+ ...opts.postTweetRequest,
8
+ };
9
+ }
10
+
11
+ export async function list(opts = {}) {
12
+ const res = await this.graphql("FetchDraftTweets", {
13
+ variables: { ascending: opts.ascending ?? false, ...opts.variables },
14
+ });
15
+ return res?.data?.viewer?.draft_list?.response_data ?? res;
16
+ }
17
+
18
+ export async function create(text, opts = {}) {
19
+ return await this.graphql("CreateDraftTweet", {
20
+ body: { variables: { post_tweet_request: buildPostTweetRequest(text, opts) } },
21
+ });
22
+ }
23
+
24
+ export async function edit(draftId, text, opts = {}) {
25
+ if (!draftId) throw new Error("edit requires a draftId");
26
+ return await this.graphql("EditDraftTweet", {
27
+ body: {
28
+ variables: { draft_tweet_id: draftId, post_tweet_request: buildPostTweetRequest(text, opts) },
29
+ },
30
+ });
31
+ }
32
+
33
+ export async function remove(draftId) {
34
+ if (!draftId) throw new Error("remove requires a draftId");
35
+ return await this.graphql("DeleteDraftTweet", {
36
+ body: { variables: { draft_tweet_id: draftId } },
37
+ });
38
+ }
@@ -0,0 +1,19 @@
1
+ export async function media(pinnedTweetId, opts = {}) {
2
+ if (!pinnedTweetId) throw new Error("media requires a pinnedTweetId");
3
+ const res = await this.graphql("ImmersiveMedia", {
4
+ variables: {
5
+ pinned_tweet_id: pinnedTweetId,
6
+ page_name: opts.pageName ?? "immersive_video",
7
+ ...opts.variables,
8
+ },
9
+ });
10
+ return res?.data?.immersiveMedia ?? res;
11
+ }
12
+
13
+ export async function profile(pinnedTweetId, opts = {}) {
14
+ if (!pinnedTweetId) throw new Error("profile requires a pinnedTweetId");
15
+ const res = await this.graphql("ImmersiveProfile", {
16
+ variables: { pinned_tweet_id: pinnedTweetId, ...opts.variables },
17
+ });
18
+ return res?.data?.immersiveProfile ?? res;
19
+ }
@@ -4,7 +4,9 @@ import * as bookmarks from "./bookmarks.js";
4
4
  import * as communities from "./communities.js";
5
5
  import * as delegates from "./delegates.js";
6
6
  import * as dms from "./dms.js";
7
+ import * as drafts from "./drafts.js";
7
8
  import * as grok from "./grok.js";
9
+ import * as immersive from "./immersive.js";
8
10
  import * as jetfuel from "./jetfuel.js";
9
11
  import * as lists from "./lists.js";
10
12
  import * as media from "./media.js";
@@ -60,4 +62,6 @@ export default function initHelpers(proto) {
60
62
  namespace(proto, "articles", articles);
61
63
  namespace(proto, "notes", notes);
62
64
  namespace(proto, "delegates", delegates);
65
+ namespace(proto, "drafts", drafts);
66
+ namespace(proto, "immersive", immersive);
63
67
  }
@@ -80,3 +80,9 @@ export async function creatorSubscriptions(opts = {}) {
80
80
  });
81
81
  return parseTimeline(raw);
82
82
  }
83
+
84
+ export async function updatePinned(pinnedTimelineItems) {
85
+ return await this.graphql("UpdatePinnedTimelines", {
86
+ body: { variables: { pinnedTimelineItems } },
87
+ });
88
+ }
@@ -409,3 +409,23 @@ export async function similar(tweetId) {
409
409
  variables: { tweet_id: tweetId },
410
410
  });
411
411
  }
412
+
413
+ export async function downvote(tweetId) {
414
+ return await this.graphql("DownvoteTweet", { body: { variables: { tweet_id: tweetId } } });
415
+ }
416
+
417
+ export async function undoDownvote(tweetId) {
418
+ return await this.graphql("UndoDownvoteTweet", { body: { variables: { tweet_id: tweetId } } });
419
+ }
420
+
421
+ export async function addContentDisclosure(tweetId, opts = {}) {
422
+ return await this.graphql("AddContentDisclosure", {
423
+ body: { variables: { tweet_id: tweetId, ...opts.variables } },
424
+ });
425
+ }
426
+
427
+ export async function removeContentDisclosure(tweetId, opts = {}) {
428
+ return await this.graphql("DeleteContentDisclosure", {
429
+ body: { variables: { tweet_id: tweetId, ...opts.variables } },
430
+ });
431
+ }