rettiwt-api 1.1.5 → 1.1.7
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/dist/graphql/enums/Errors.d.ts +1 -0
- package/dist/graphql/enums/Errors.js +1 -0
- package/dist/graphql/enums/Errors.js.map +1 -1
- package/dist/graphql/resolvers/UserResolver.d.ts +9 -0
- package/dist/graphql/resolvers/UserResolver.js +61 -0
- package/dist/graphql/resolvers/UserResolver.js.map +1 -1
- package/dist/graphql/types/UserTypes.js +1 -1
- package/dist/graphql/types/UserTypes.js.map +1 -1
- package/dist/requests/payloads/Variables.d.ts +23 -0
- package/dist/requests/payloads/Variables.js +24 -0
- package/dist/requests/payloads/Variables.js.map +1 -0
- package/dist/services/data/TweetService.d.ts +1 -1
- package/dist/services/data/TweetService.js +1 -1
- package/dist/services/data/TweetService.js.map +1 -1
- package/dist/services/data/UserService.d.ts +15 -0
- package/dist/services/data/UserService.js +33 -0
- package/dist/services/data/UserService.js.map +1 -1
- package/dist/services/helper/extractors/Users.d.ts +6 -0
- package/dist/services/helper/extractors/Users.js +53 -1
- package/dist/services/helper/extractors/Users.js.map +1 -1
- package/dist/services/helper/urls/Users.d.ts +8 -1
- package/dist/services/helper/urls/Users.js +12 -2
- package/dist/services/helper/urls/Users.js.map +1 -1
- package/dist/types/Query.d.ts +80 -0
- package/dist/types/Query.js +3 -0
- package/dist/types/Query.js.map +1 -0
- package/dist/types/raw/data/tweet/Favouriters.d.ts +164 -0
- package/dist/types/raw/data/tweet/Favouriters.js +3 -0
- package/dist/types/raw/data/tweet/Favouriters.js.map +1 -0
- package/dist/types/raw/data/tweet/Retweeters.d.ts +171 -0
- package/dist/types/raw/data/tweet/Retweeters.js +3 -0
- package/dist/types/raw/data/tweet/Retweeters.js.map +1 -0
- package/dist/types/raw/data/tweet/Tweet.d.ts +746 -0
- package/dist/types/raw/data/tweet/Tweet.js +3 -0
- package/dist/types/raw/data/tweet/Tweet.js.map +1 -0
- package/dist/types/raw/data/tweet/Tweets.d.ts +386 -0
- package/dist/types/raw/data/tweet/Tweets.js +3 -0
- package/dist/types/raw/data/tweet/Tweets.js.map +1 -0
- package/dist/types/raw/data/user/Followers.d.ts +176 -0
- package/dist/types/raw/data/user/Followers.js +3 -0
- package/dist/types/raw/data/user/Followers.js.map +1 -0
- package/dist/types/raw/data/user/Following.d.ts +176 -0
- package/dist/types/raw/data/user/Following.js +3 -0
- package/dist/types/raw/data/user/Following.js.map +1 -0
- package/dist/types/raw/data/user/Likes.d.ts +1059 -0
- package/dist/types/raw/data/user/Likes.js +3 -0
- package/dist/types/raw/data/user/Likes.js.map +1 -0
- package/dist/types/raw/data/user/User.d.ts +117 -0
- package/dist/types/raw/data/user/User.js +3 -0
- package/dist/types/raw/data/user/User.js.map +1 -0
- package/dist/types/raw/query/tweet/Details.d.ts +80 -0
- package/dist/types/raw/query/tweet/Details.js +5 -0
- package/dist/types/raw/query/tweet/Details.js.map +1 -0
- package/dist/types/raw/query/tweet/Engagements.d.ts +29 -0
- package/dist/types/raw/query/tweet/Engagements.js +3 -0
- package/dist/types/raw/query/tweet/Engagements.js.map +1 -0
- package/dist/types/raw/query/tweet/Likes.d.ts +29 -0
- package/dist/types/raw/query/tweet/Likes.js +3 -0
- package/dist/types/raw/query/tweet/Likes.js.map +1 -0
- package/dist/types/raw/query/tweet/Retweets.d.ts +29 -0
- package/dist/types/raw/query/tweet/Retweets.js +3 -0
- package/dist/types/raw/query/tweet/Retweets.js.map +1 -0
- package/dist/types/raw/query/tweet/Search.d.ts +40 -0
- package/dist/types/raw/query/tweet/Search.js +3 -0
- package/dist/types/raw/query/tweet/Search.js.map +1 -0
- package/dist/types/raw/query/tweet/TweetLike.d.ts +29 -0
- package/dist/types/raw/query/tweet/TweetLike.js +3 -0
- package/dist/types/raw/query/tweet/TweetLike.js.map +1 -0
- package/dist/types/raw/query/tweet/TweetLikes.d.ts +29 -0
- package/dist/types/raw/query/tweet/TweetLikes.js +3 -0
- package/dist/types/raw/query/tweet/TweetLikes.js.map +1 -0
- package/dist/types/raw/query/tweet/TweetRetweets.d.ts +0 -0
- package/dist/types/raw/query/tweet/TweetRetweets.js +2 -0
- package/dist/types/raw/query/tweet/TweetRetweets.js.map +1 -0
- package/dist/types/raw/query/user/Details.d.ts +34 -0
- package/dist/types/raw/query/user/Details.js +3 -0
- package/dist/types/raw/query/user/Details.js.map +1 -0
- package/dist/types/raw/user/Tweets.d.ts +668 -1584
- package/dist/types/raw/user/User.js.map +1 -1
- package/package.json +2 -2
- package/src/graphql/enums/Errors.ts +1 -0
- package/src/graphql/resolvers/UserResolver.ts +58 -1
- package/src/graphql/types/UserTypes.ts +3 -3
- package/src/services/data/TweetService.ts +5 -5
- package/src/services/data/UserService.ts +34 -0
- package/src/services/helper/extractors/Users.ts +55 -0
- package/src/services/helper/urls/Users.ts +39 -23
- package/src/types/raw/user/Tweets.ts +1747 -0
- package/docs/.nojekyll +0 -1
- package/docs/assets/highlight.css +0 -64
- package/docs/assets/main.js +0 -58
- package/docs/assets/search.js +0 -1
- package/docs/assets/style.css +0 -1280
- package/docs/classes/AccountService.html +0 -303
- package/docs/classes/AuthCookie.html +0 -146
- package/docs/classes/AuthService.html +0 -147
- package/docs/classes/CacheService.html +0 -157
- package/docs/classes/Cursor.html +0 -102
- package/docs/classes/CursoredData.html +0 -126
- package/docs/classes/DataValidationError.html +0 -119
- package/docs/classes/FetcherService.html +0 -225
- package/docs/classes/Tweet.html +0 -210
- package/docs/classes/TweetEntities.html +0 -128
- package/docs/classes/TweetFilter.html +0 -204
- package/docs/classes/TweetListArgs.html +0 -118
- package/docs/classes/TweetService.html +0 -313
- package/docs/classes/User.html +0 -230
- package/docs/classes/UserListArgs.html +0 -118
- package/docs/classes/UserService.html +0 -315
- package/docs/enums/HttpMethods.html +0 -74
- package/docs/functions/Rettiwt.html +0 -99
- package/docs/index.html +0 -161
- package/docs/interfaces/IAuthCookie.html +0 -104
- package/docs/interfaces/ICursor.html +0 -77
- package/docs/interfaces/ICursoredData.html +0 -93
- package/docs/interfaces/IDataContext.html +0 -91
- package/docs/interfaces/IListArgs.html +0 -87
- package/docs/interfaces/ITweet.html +0 -176
- package/docs/interfaces/ITweetEntities.html +0 -104
- package/docs/interfaces/ITweetFilter.html +0 -158
- package/docs/interfaces/IUser.html +0 -194
- package/docs/modules.html +0 -109
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"User.js","sourceRoot":"","sources":["../../../../src/types/raw/
|
|
1
|
+
{"version":3,"file":"User.js","sourceRoot":"","sources":["../../../../src/types/raw/user/User.ts"],"names":[],"mappings":""}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rettiwt-api",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.7",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"description": "An API for fetching data from TwitterAPI, without any rate limits!",
|
|
@@ -43,4 +43,4 @@
|
|
|
43
43
|
"typedoc": "0.23.26",
|
|
44
44
|
"typescript": "4.6.4"
|
|
45
45
|
}
|
|
46
|
-
}
|
|
46
|
+
}
|
|
@@ -16,6 +16,7 @@ export enum DataErrors {
|
|
|
16
16
|
NoTweetsFound = "No tweets matching the given criteria found",
|
|
17
17
|
NoLikersFound = "No likers found for the tweet with the given id",
|
|
18
18
|
NoRetweetersFound = "No retweeters found for the tweet with the given id",
|
|
19
|
+
NoUserTweetsFound = "No tweets were found for the user with the given id",
|
|
19
20
|
NoFollowsFound = "No follow details were found for the user with the given id",
|
|
20
21
|
NoLikedTweetsFound = "No liked tweets were found for the user with the given id"
|
|
21
22
|
};
|
|
@@ -9,7 +9,7 @@ import { DataErrors } from '../enums/Errors';
|
|
|
9
9
|
export default class UserResolver extends ResolverBase {
|
|
10
10
|
// MEMBER DATA
|
|
11
11
|
private batchSize: number; // To store the batch size when fetching data
|
|
12
|
-
|
|
12
|
+
|
|
13
13
|
// MEMBER METHODS
|
|
14
14
|
constructor(context: IDataContext) {
|
|
15
15
|
super(context);
|
|
@@ -27,6 +27,63 @@ export default class UserResolver extends ResolverBase {
|
|
|
27
27
|
});
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
/**
|
|
31
|
+
* @returns The list of tweets made by the given user
|
|
32
|
+
* @param id The id of the user whose tweets are to be fetched
|
|
33
|
+
* @param count The number of tweets to fetch, must be >= 40
|
|
34
|
+
* @param all Whether to fetch list of all tweets made by user
|
|
35
|
+
* @param cursor The cursor to the batch of tweets to fetch
|
|
36
|
+
* @param statusesCount The total number of tweets made by target user
|
|
37
|
+
*/
|
|
38
|
+
async resolveUserTweets(id: string, count: number, all: boolean, cursor: string, statusesCount: number): Promise<any> {
|
|
39
|
+
let likes: any[] = []; // To store the list of tweets
|
|
40
|
+
let next: Cursor = new Cursor(cursor); // To store cursor to next batch
|
|
41
|
+
let total: number = 0; // To store the total number of tweets fetched
|
|
42
|
+
|
|
43
|
+
// If all tweets are to be fetched
|
|
44
|
+
count = all ? statusesCount : count;
|
|
45
|
+
|
|
46
|
+
// If required count less than batch size, setting batch size to required count
|
|
47
|
+
this.batchSize = (count < this.batchSize) ? count : this.batchSize;
|
|
48
|
+
|
|
49
|
+
// Repeatedly fetching data as long as total data fetched is less than requried
|
|
50
|
+
do {
|
|
51
|
+
// If this is the last batch, change batch size to number of remaining tweets
|
|
52
|
+
this.batchSize = ((count - total) < this.batchSize) ? (count - total) : this.batchSize;
|
|
53
|
+
|
|
54
|
+
// Getting the data
|
|
55
|
+
const res = await this.context.users.getUserTweets(id, this.batchSize, next.value).catch(error => {
|
|
56
|
+
throw this.getGraphQLError(error);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// If data is available
|
|
60
|
+
if (res.list?.length) {
|
|
61
|
+
// Adding fetched tweets to list of tweets
|
|
62
|
+
likes = likes.concat(res.list);
|
|
63
|
+
|
|
64
|
+
// Updating total tweets fetched
|
|
65
|
+
total = likes.length;
|
|
66
|
+
|
|
67
|
+
// Getting cursor to next batch
|
|
68
|
+
next = res.next as Cursor;
|
|
69
|
+
}
|
|
70
|
+
// If no more data is available
|
|
71
|
+
else {
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
} while (total < count);
|
|
75
|
+
|
|
76
|
+
// If no likes found
|
|
77
|
+
if (!likes.length) {
|
|
78
|
+
return new Error(DataErrors.NoUserTweetsFound);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Adding the cursor to the end of list of data
|
|
82
|
+
likes.push(next);
|
|
83
|
+
|
|
84
|
+
return likes;
|
|
85
|
+
}
|
|
86
|
+
|
|
30
87
|
/**
|
|
31
88
|
* @returns The list of tweets liked by the given user
|
|
32
89
|
* @param id The id of the user whose likes are to be fetched
|
|
@@ -113,7 +113,7 @@ export const User: GraphQLObjectType = new GraphQLObjectType({
|
|
|
113
113
|
defaultValue: ''
|
|
114
114
|
}
|
|
115
115
|
},
|
|
116
|
-
resolve: (parent, args, context) => new
|
|
116
|
+
resolve: (parent, args, context) => new UserResolver(context).resolveUserTweets(parent.id, args.count, args.all, args.cursor, parent.statusesCount)
|
|
117
117
|
}
|
|
118
118
|
})
|
|
119
119
|
});
|
|
@@ -124,11 +124,11 @@ export const UserList: GraphQLList<GraphQLType> = new GraphQLList(new GraphQLUni
|
|
|
124
124
|
types: [User, Cursor],
|
|
125
125
|
resolveType: (data) => {
|
|
126
126
|
// If it has a userName field => this is a User object
|
|
127
|
-
if(data.userName) {
|
|
127
|
+
if (data.userName) {
|
|
128
128
|
return User;
|
|
129
129
|
}
|
|
130
130
|
// If it has a value field => this is a Cursor object
|
|
131
|
-
else if(data.value) {
|
|
131
|
+
else if (data.value) {
|
|
132
132
|
return Cursor;
|
|
133
133
|
}
|
|
134
134
|
}
|
|
@@ -51,7 +51,7 @@ export class TweetService extends FetcherService {
|
|
|
51
51
|
*
|
|
52
52
|
* @remarks
|
|
53
53
|
*
|
|
54
|
-
*
|
|
54
|
+
* Cookies are required to use this method!
|
|
55
55
|
*/
|
|
56
56
|
async getTweets(query: TweetFilter, count?: number, cursor?: string): Promise<CursoredData<Tweet>> {
|
|
57
57
|
// Objectifying parameters
|
|
@@ -95,7 +95,7 @@ export class TweetService extends FetcherService {
|
|
|
95
95
|
if (cachedData) {
|
|
96
96
|
return cachedData;
|
|
97
97
|
}
|
|
98
|
-
|
|
98
|
+
|
|
99
99
|
// Fetching the raw data
|
|
100
100
|
let res = await this.request<RawTweet>(TweetUrls.tweetDetailsUrl(id), false).then(res => res.data);
|
|
101
101
|
|
|
@@ -128,13 +128,13 @@ export class TweetService extends FetcherService {
|
|
|
128
128
|
*/
|
|
129
129
|
async getTweetLikers(tweetId: string, count?: number, cursor?: string): Promise<CursoredData<User>> {
|
|
130
130
|
// If user is not authenticated, abort
|
|
131
|
-
if(!this.isAuthenticated) {
|
|
131
|
+
if (!this.isAuthenticated) {
|
|
132
132
|
throw new Error(AuthenticationErrors.NotAuthenticated);
|
|
133
133
|
}
|
|
134
134
|
|
|
135
135
|
// Objectifying parameters
|
|
136
136
|
let args: TweetListArgs = new TweetListArgs(count, cursor);
|
|
137
|
-
|
|
137
|
+
|
|
138
138
|
// Fetching the raw data
|
|
139
139
|
let res = await this.request<RawLikers>(TweetUrls.tweetLikesUrl(tweetId, args.count, args.cursor)).then(res => res.data);
|
|
140
140
|
|
|
@@ -167,7 +167,7 @@ export class TweetService extends FetcherService {
|
|
|
167
167
|
*/
|
|
168
168
|
async getTweetRetweeters(tweetId: string, count?: number, cursor?: string): Promise<CursoredData<User>> {
|
|
169
169
|
// If user is not authenticated, abort
|
|
170
|
-
if(!this.isAuthenticated) {
|
|
170
|
+
if (!this.isAuthenticated) {
|
|
171
171
|
throw new Error(AuthenticationErrors.NotAuthenticated);
|
|
172
172
|
}
|
|
173
173
|
|
|
@@ -11,6 +11,7 @@ import { Tweet } from '../../models/data/Tweet';
|
|
|
11
11
|
import { CursoredData } from '../../models/data/CursoredData';
|
|
12
12
|
import { Result as TweetData } from '../../types/raw/tweet/Tweet';
|
|
13
13
|
import RawUser, { Result as UserData } from '../../types/raw/user/User';
|
|
14
|
+
import RawUserTweets from '../../types/raw/user/Tweets';
|
|
14
15
|
import RawUserFollowers from '../../types/raw/user/Followers';
|
|
15
16
|
import RawUserFollowing from '../../types/raw/user/Following';
|
|
16
17
|
import RawUserLikes from '../../types/raw/user/Likes';
|
|
@@ -80,6 +81,39 @@ export class UserService extends FetcherService {
|
|
|
80
81
|
return user;
|
|
81
82
|
}
|
|
82
83
|
|
|
84
|
+
/**
|
|
85
|
+
* @param userId The rest id of the target user.
|
|
86
|
+
* @param count The number of tweets to fetch, must be >= 40 (when no cursor is provided) and <=100.
|
|
87
|
+
* @param cursor The cursor to next batch. If blank, first batch is fetched.
|
|
88
|
+
*
|
|
89
|
+
* @returns The list of tweets nade by the target user.
|
|
90
|
+
*
|
|
91
|
+
* @throws {@link Errors.ValidationErrors.InvalidCount} error, if invalid count has been provided.
|
|
92
|
+
* @throws {@link Errors.DataErrors.UserNotFound} error, if invalid count has been provided.
|
|
93
|
+
*
|
|
94
|
+
* @remarks
|
|
95
|
+
*
|
|
96
|
+
* No cookies are required to use this method.
|
|
97
|
+
*/
|
|
98
|
+
async getUserTweets(userId: string, count?: number, cursor?: string): Promise<CursoredData<Tweet>> {
|
|
99
|
+
// Objectifying parameters
|
|
100
|
+
let args: UserListArgs = new UserListArgs(count, cursor);
|
|
101
|
+
|
|
102
|
+
// Fetching the raw data
|
|
103
|
+
let res = await this.request<RawUserTweets>(UserUrls.userTweetsUrl(userId, args.count, args.cursor), false).then(res => res.data);
|
|
104
|
+
|
|
105
|
+
// Extracting data
|
|
106
|
+
let data = UserExtractors.extractUserTweets(res);
|
|
107
|
+
|
|
108
|
+
// Caching data
|
|
109
|
+
this.cacheData(data);
|
|
110
|
+
|
|
111
|
+
// Parsing data
|
|
112
|
+
let tweets = data.required.map((item: TweetData) => new Tweet(item));
|
|
113
|
+
|
|
114
|
+
return new CursoredData<Tweet>(tweets, data.cursor);
|
|
115
|
+
}
|
|
116
|
+
|
|
83
117
|
/**
|
|
84
118
|
* @param userId The rest id of the target user.
|
|
85
119
|
* @param count The number of following to fetch, must be >= 40 (when no cursor is provided) and <=100.
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { IDataExtract } from '../../../types/Resolvers'
|
|
3
3
|
import { DataErrors } from '../../../enums/Errors';
|
|
4
4
|
import RawUser from '../../../types/raw/user/User';
|
|
5
|
+
import RawUserTweets from '../../../types/raw/user/Tweets';
|
|
5
6
|
import RawUserFollowers from '../../../types/raw/user/Followers';
|
|
6
7
|
import RawUserFollowing from '../../../types/raw/user/Following';
|
|
7
8
|
import RawUserLikes from '../../../types/raw/user/Likes';
|
|
@@ -37,6 +38,60 @@ export function extractUserDetails(res: RawUser): IDataExtract {
|
|
|
37
38
|
};
|
|
38
39
|
}
|
|
39
40
|
|
|
41
|
+
/**
|
|
42
|
+
* @returns The raw user tweet data formatted and sorted into required and additional data
|
|
43
|
+
* @param res The raw response received from Twitter
|
|
44
|
+
*/
|
|
45
|
+
export function extractUserTweets(res: RawUserTweets): IDataExtract {
|
|
46
|
+
let required: any[] = []; // To store the reqruied raw data
|
|
47
|
+
let cursor: string = ''; // To store the cursor to next batch
|
|
48
|
+
let users: any[] = []; // To store additional user data
|
|
49
|
+
let tweets: any[] = []; // To store additional tweet data
|
|
50
|
+
|
|
51
|
+
// If user does not exist
|
|
52
|
+
if (Parsers.isJSONEmpty(res.data.user)) {
|
|
53
|
+
throw new Error(DataErrors.UserNotFound);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Extracting the raw list
|
|
57
|
+
res.data.user.result.timeline_v2.timeline.instructions.forEach(item => {
|
|
58
|
+
if (item.type === 'TimelineAddEntries') {
|
|
59
|
+
// If no tweets found
|
|
60
|
+
if (item.entries?.length == 2) {
|
|
61
|
+
// Returning the data
|
|
62
|
+
return {
|
|
63
|
+
required: required,
|
|
64
|
+
cursor: cursor,
|
|
65
|
+
users: users,
|
|
66
|
+
tweets: tweets
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Destructuring data
|
|
71
|
+
item.entries.forEach(entry => {
|
|
72
|
+
// If entry is of type tweet and tweet exists
|
|
73
|
+
if (entry.entryId.indexOf('tweet') != -1 && entry.content.itemContent?.tweet_results.result.__typename === 'Tweet') {
|
|
74
|
+
required.push(entry.content.itemContent.tweet_results.result);
|
|
75
|
+
users.push(entry.content.itemContent.tweet_results.result.core.user_results.result);
|
|
76
|
+
tweets.push(entry.content.itemContent.tweet_results.result);
|
|
77
|
+
}
|
|
78
|
+
// If entry is of type cursor
|
|
79
|
+
else if (entry.entryId.indexOf('cursor-bottom') != -1) {
|
|
80
|
+
cursor = entry.content.value ?? '';
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// Returning the data
|
|
87
|
+
return {
|
|
88
|
+
required: required,
|
|
89
|
+
cursor: cursor,
|
|
90
|
+
users: users,
|
|
91
|
+
tweets: tweets
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
40
95
|
/**
|
|
41
96
|
* @returns The raw user following/followers data formatted and sorted into required and additional data
|
|
42
97
|
* @param res The raw response received from TwitterAPI
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* @param screenName The screen name of the target user
|
|
4
4
|
*/
|
|
5
5
|
export function userDetailsUrl(screenName: string): string {
|
|
6
|
-
|
|
6
|
+
return `https://api.twitter.com/graphql/hVhfo_TquFTmgL7gYwf91Q/UserByScreenName?variables=%7B%22screen_name%22%3A%22${screenName}%22%2C%22withSafetyModeUserFields%22%3Atrue%2C%22withSuperFollowsUserFields%22%3Atrue%7D&features=%7B%22responsive_web_twitter_blue_verified_badge_is_enabled%22%3Atrue%2C%22verified_phone_label_enabled%22%3Atrue%2C%22responsive_web_graphql_timeline_navigation_enabled%22%3Atrue%7D`;
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
/**
|
|
@@ -11,23 +11,35 @@ export function userDetailsUrl(screenName: string): string {
|
|
|
11
11
|
* @param restid The restId of the target user
|
|
12
12
|
*/
|
|
13
13
|
export function userDetailsByIdUrl(restId: string): string {
|
|
14
|
-
|
|
14
|
+
return `https://api.twitter.com/graphql/mi_IjXgFyr41N9zkszPz9w/UserByRestId?variables=%7B%22userId%22%3A%22${restId}%22%2C%22withSafetyModeUserFields%22%3Atrue%2C%22withSuperFollowsUserFields%22%3Atrue%7D&features=%7B%22responsive_web_twitter_blue_verified_badge_is_enabled%22%3Atrue%2C%22verified_phone_label_enabled%22%3Atrue%2C%22responsive_web_graphql_timeline_navigation_enabled%22%3Atrue%7D`;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
|
-
* @returns The url for fetching the list of
|
|
18
|
+
* @returns The url for fetching the list of tweet made by target user.
|
|
19
|
+
* @param userId The rest id of the target user
|
|
20
|
+
* @param count The batch size of the list of tweets, should be >= 40 and <=100
|
|
21
|
+
* @param cursor The cursor to next batch
|
|
22
|
+
*/
|
|
23
|
+
export function userTweetsUrl(userId: string, count: number, cursor: string): string {
|
|
24
|
+
return `https://api.twitter.com/graphql/xxLjoOBBPpYBHbBTI-hevQ/UserTweetsAndReplies?variables=%7B%22userId%22%3A%22${userId}%22%2C%22count%22%3A${count}%2C%22cursor%22%3A%22${cursor}%22%2C%22includePromotedContent%22%3Atrue%2C%22withCommunity%22%3Atrue%2C%22withSuperFollowsUserFields%22%3Atrue%2C%22withDownvotePerspective%22%3Afalse%2C%22withReactionsMetadata%22%3Afalse%2C%22withReactionsPerspective%22%3Afalse%2C%22withSuperFollowsTweetFields%22%3Atrue%2C%22withVoice%22%3Atrue%2C%22withV2Timeline%22%3Atrue%7D&features=%7B%22responsive_web_twitter_blue_verified_badge_is_enabled%22%3Atrue%2C%22verified_phone_label_enabled%22%3Atrue%2C%22responsive_web_graphql_timeline_navigation_enabled%22%3Atrue%2C%22view_counts_public_visibility_enabled%22%3Atrue%2C%22longform_notetweets_consumption_enabled%22%3Afalse%2C%22tweetypie_unmention_optimization_enabled%22%3Atrue%2C%22vibe_api_enabled%22%3Atrue%2C%22responsive_web_edit_tweet_api_enabled%22%3Atrue%2C%22graphql_is_translatable_rweb_tweet_is_translatable_enabled%22%3Atrue%2C%22view_counts_everywhere_api_enabled%22%3Atrue%2C%22standardized_nudges_misinfo%22%3Atrue%2C%22tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled%22%3Afalse%2C%22interactive_text_enabled%22%3Atrue%2C%22responsive_web_text_conversations_enabled%22%3Afalse%2C%22responsive_web_enhance_cards_enabled%22%3Afalse%7D`;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @returns The url for fetching the list of users followed by target user.
|
|
19
29
|
* @param userId The rest id of the target user
|
|
20
30
|
* @param count The batch size of the list of following, should be >= 40 and <=100
|
|
21
31
|
* @param cursor The cursor to next batch
|
|
22
32
|
*/
|
|
23
33
|
export function userFollowingUrl(userId: string, count: number, cursor: string): string {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
34
|
+
/**
|
|
35
|
+
* Twitter has a ver odd behaviour here.
|
|
36
|
+
* If no cursor is provided, the number of followings fetched is slightly more the given count.
|
|
37
|
+
* If a cursor if provided, the number of followings is sometimes less than the provided count.
|
|
38
|
+
* NO SOLUTION EXISTS AS OF NOW!
|
|
39
|
+
*/
|
|
40
|
+
return `https://api.twitter.com/graphql/mSnjZc5CTm2Z5Lu_i4XsPQ/Following?variables=%7B%22userId%22%3A%22${userId}%22%2C%22count%22%3A${count}%2C%22cursor%22%3A%22${encodeURIComponent(
|
|
41
|
+
cursor,
|
|
42
|
+
)}%22%2C%22includePromotedContent%22%3Afalse%2C%22withSuperFollowsUserFields%22%3Atrue%2C%22withDownvotePerspective%22%3Afalse%2C%22withReactionsMetadata%22%3Afalse%2C%22withReactionsPerspective%22%3Afalse%2C%22withSuperFollowsTweetFields%22%3Atrue%7D&features=%7B%22responsive_web_twitter_blue_verified_badge_is_enabled%22%3Atrue%2C%22verified_phone_label_enabled%22%3Atrue%2C%22responsive_web_graphql_timeline_navigation_enabled%22%3Atrue%2C%22view_counts_public_visibility_enabled%22%3Atrue%2C%22longform_notetweets_consumption_enabled%22%3Afalse%2C%22tweetypie_unmention_optimization_enabled%22%3Atrue%2C%22responsive_web_uc_gql_enabled%22%3Atrue%2C%22vibe_api_enabled%22%3Atrue%2C%22responsive_web_edit_tweet_api_enabled%22%3Atrue%2C%22graphql_is_translatable_rweb_tweet_is_translatable_enabled%22%3Atrue%2C%22view_counts_everywhere_api_enabled%22%3Atrue%2C%22standardized_nudges_misinfo%22%3Atrue%2C%22tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled%22%3Afalse%2C%22interactive_text_enabled%22%3Atrue%2C%22responsive_web_text_conversations_enabled%22%3Afalse%2C%22responsive_web_enhance_cards_enabled%22%3Afalse%7D`;
|
|
31
43
|
}
|
|
32
44
|
|
|
33
45
|
/**
|
|
@@ -37,18 +49,20 @@ export function userFollowingUrl(userId: string, count: number, cursor: string):
|
|
|
37
49
|
* @param cursor The cusor to next batch
|
|
38
50
|
*/
|
|
39
51
|
export function userFollowersUrl(userId: string, count: number, cursor: string): string {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
52
|
+
/**
|
|
53
|
+
* Twitter has a very odd behaviour here.
|
|
54
|
+
* If no cursor is provided, the number of followers fetched is equal to count + 20.
|
|
55
|
+
* If a cursor is provided, the number of followers fetched is equal to count.
|
|
56
|
+
* The solution is to check accordingly, if a cursor if provided or not and manipulate the count
|
|
57
|
+
*/
|
|
58
|
+
// If no cursor if provided
|
|
59
|
+
if (!cursor) {
|
|
60
|
+
count = count - 20;
|
|
61
|
+
}
|
|
50
62
|
|
|
51
|
-
|
|
63
|
+
return `https://api.twitter.com/graphql/nwlAnaw7oKXcVLi91ehy7Q/Followers?variables=%7B%22userId%22%3A%22${userId}%22%2C%22count%22%3A${count}%2C%22cursor%22%3A%22${encodeURIComponent(
|
|
64
|
+
cursor,
|
|
65
|
+
)}%22%2C%22includePromotedContent%22%3Afalse%2C%22withSuperFollowsUserFields%22%3Atrue%2C%22withDownvotePerspective%22%3Afalse%2C%22withReactionsMetadata%22%3Afalse%2C%22withReactionsPerspective%22%3Afalse%2C%22withSuperFollowsTweetFields%22%3Atrue%7D&features=%7B%22responsive_web_twitter_blue_verified_badge_is_enabled%22%3Atrue%2C%22verified_phone_label_enabled%22%3Atrue%2C%22responsive_web_graphql_timeline_navigation_enabled%22%3Atrue%2C%22view_counts_public_visibility_enabled%22%3Atrue%2C%22longform_notetweets_consumption_enabled%22%3Afalse%2C%22tweetypie_unmention_optimization_enabled%22%3Atrue%2C%22responsive_web_uc_gql_enabled%22%3Atrue%2C%22vibe_api_enabled%22%3Atrue%2C%22responsive_web_edit_tweet_api_enabled%22%3Atrue%2C%22graphql_is_translatable_rweb_tweet_is_translatable_enabled%22%3Atrue%2C%22view_counts_everywhere_api_enabled%22%3Atrue%2C%22standardized_nudges_misinfo%22%3Atrue%2C%22tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled%22%3Afalse%2C%22interactive_text_enabled%22%3Atrue%2C%22responsive_web_text_conversations_enabled%22%3Afalse%2C%22responsive_web_enhance_cards_enabled%22%3Afalse%7D`;
|
|
52
66
|
}
|
|
53
67
|
|
|
54
68
|
/**
|
|
@@ -58,5 +72,7 @@ export function userFollowersUrl(userId: string, count: number, cursor: string):
|
|
|
58
72
|
* @param cursor The cusor to next batch
|
|
59
73
|
*/
|
|
60
74
|
export function userLikesUrl(userId: string, count: number, cursor: string): string {
|
|
61
|
-
|
|
62
|
-
|
|
75
|
+
return `https://api.twitter.com/graphql/gP4ZKghLd4tpILgS6VudAQ/Likes?variables=%7B%22userId%22%3A%22${userId}%22%2C%22count%22%3A${count}%2C%22cursor%22%3A%22${encodeURIComponent(
|
|
76
|
+
cursor,
|
|
77
|
+
)}%22%2C%22includePromotedContent%22%3Afalse%2C%22withSuperFollowsUserFields%22%3Atrue%2C%22withDownvotePerspective%22%3Afalse%2C%22withReactionsMetadata%22%3Afalse%2C%22withReactionsPerspective%22%3Afalse%2C%22withSuperFollowsTweetFields%22%3Atrue%2C%22withClientEventToken%22%3Afalse%2C%22withBirdwatchNotes%22%3Afalse%2C%22withVoice%22%3Atrue%2C%22withV2Timeline%22%3Atrue%7D&features=%7B%22responsive_web_twitter_blue_verified_badge_is_enabled%22%3Atrue%2C%22verified_phone_label_enabled%22%3Atrue%2C%22responsive_web_graphql_timeline_navigation_enabled%22%3Atrue%2C%22view_counts_public_visibility_enabled%22%3Atrue%2C%22longform_notetweets_consumption_enabled%22%3Afalse%2C%22tweetypie_unmention_optimization_enabled%22%3Atrue%2C%22responsive_web_uc_gql_enabled%22%3Atrue%2C%22vibe_api_enabled%22%3Atrue%2C%22responsive_web_edit_tweet_api_enabled%22%3Atrue%2C%22graphql_is_translatable_rweb_tweet_is_translatable_enabled%22%3Atrue%2C%22view_counts_everywhere_api_enabled%22%3Atrue%2C%22standardized_nudges_misinfo%22%3Atrue%2C%22tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled%22%3Afalse%2C%22interactive_text_enabled%22%3Atrue%2C%22responsive_web_text_conversations_enabled%22%3Afalse%2C%22responsive_web_enhance_cards_enabled%22%3Afalse%7D`;
|
|
78
|
+
}
|