gs-x-parser 1.0.1 → 1.0.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/lib/parser.mjs CHANGED
@@ -1,191 +1,286 @@
1
+ import { IdPrefixes } from './type.mjs';
2
+ function filterTweets(convertedTweets, originalTweets, options) {
3
+ const tweets = [], ads = [], exploreMore = [], recommendations = [];
4
+ return convertedTweets.forEach((tweet, index) => {
5
+ const originalTweet = originalTweets[index], restId = originalTweet?.rest_id || "", entryId = originalTweet?.entryId || "";
6
+ restId.startsWith(IdPrefixes.PromotedTweet) || entryId.startsWith(IdPrefixes.PromotedTweet) ? (ads.push(tweet), options.includeAds && tweets.push(tweet)) : restId.includes("explore") || entryId.includes("tweetdetailrelatedtweets") ? (exploreMore.push(tweet), options.includeExploreMore && tweets.push(tweet)) : restId.includes("recommendation") || restId.includes("suggestion") || entryId.includes("pinned-tweets") ? (recommendations.push(tweet), options.includeRecommendations && tweets.push(tweet)) : tweets.push(tweet);
7
+ }), { tweets, ads, exploreMore, recommendations };
8
+ }
9
+ function extractUsers(data) {
10
+ const users = [], userIds = /* @__PURE__ */ new Set();
11
+ data?.globalObjects?.users && Object.values(data.globalObjects.users).forEach((user) => {
12
+ user && user.id_str && !userIds.has(user.id_str) && (user.__typename = "User", user.rest_id = user.id_str, userIds.add(user.id_str), users.push(user));
13
+ }), Array.isArray(data) && data.forEach((item) => {
14
+ if (item?.user && item.user.id_str && !userIds.has(item.user.id_str)) {
15
+ const user = item.user;
16
+ user.__typename = "User", user.rest_id = user.id_str, user.ext_is_blue_verified !== void 0 && (user.is_blue_verified = user.ext_is_blue_verified), userIds.add(user.id_str), users.push(user);
17
+ }
18
+ }), data?.data?.user?.result?.timeline?.timeline?.instructions && data.data.user.result.timeline.timeline.instructions.forEach((instruction) => {
19
+ instruction.type === "TimelineAddEntries" && instruction.entries && instruction.entries.forEach((entry) => {
20
+ if (entry.content?.itemContent?.user_results?.result) {
21
+ const user = entry.content.itemContent.user_results.result;
22
+ user && user.rest_id && !userIds.has(user.rest_id) && (user.id_str || (user.id_str = user.rest_id), userIds.add(user.rest_id), users.push(user));
23
+ }
24
+ });
25
+ }), data?.data?.bookmark_timeline_v2?.timeline?.instructions && data.data.bookmark_timeline_v2.timeline.instructions.forEach((instruction) => {
26
+ instruction.type === "TimelineAddEntries" && instruction.entries && instruction.entries.forEach((entry) => {
27
+ if (entry.content?.itemContent?.tweet_results?.result?.core?.user_results?.result) {
28
+ const user = entry.content.itemContent.tweet_results.result.core.user_results.result;
29
+ user && user.rest_id && !userIds.has(user.rest_id) && (user.id_str || (user.id_str = user.rest_id), userIds.add(user.rest_id), users.push(user));
30
+ }
31
+ });
32
+ }), data?.data?.viewer_v2?.user_results?.result?.notification_timeline?.timeline?.instructions && data.data.viewer_v2.user_results.result.notification_timeline.timeline.instructions.forEach((instruction) => {
33
+ instruction.entries && instruction.entries.forEach((entry) => {
34
+ entry.content?.itemContent?.template?.from_users && entry.content.itemContent.template.from_users.forEach((fromUser) => {
35
+ if (fromUser?.user_results?.result) {
36
+ const user = fromUser.user_results.result;
37
+ user && user.rest_id && !userIds.has(user.rest_id) && (user.id_str || (user.id_str = user.rest_id), userIds.add(user.rest_id), users.push(user));
38
+ }
39
+ }), entry.content?.itemContent?.template?.target_objects && entry.content.itemContent.template.target_objects.forEach((targetObject) => {
40
+ if (targetObject?.tweet_results?.result?.core?.user_results?.result) {
41
+ const user = targetObject.tweet_results.result.core.user_results.result;
42
+ user && user.rest_id && !userIds.has(user.rest_id) && (user.id_str || (user.id_str = user.rest_id), userIds.add(user.rest_id), users.push(user));
43
+ }
44
+ });
45
+ });
46
+ });
47
+ const searchUsers = (obj) => {
48
+ if (obj && typeof obj == "object") {
49
+ const userId = obj.id_str || obj.rest_id;
50
+ obj.__typename === "User" && userId && !userIds.has(userId) && !obj.core?.user_results && !obj.legacy?.full_text && (obj.name || obj.screen_name || obj.legacy) && (obj.__typename = "User", obj.rest_id || (obj.rest_id = userId), obj.id_str || (obj.id_str = userId), obj.ext_is_blue_verified !== void 0 && (obj.is_blue_verified = obj.ext_is_blue_verified), userIds.add(userId), users.push(obj));
51
+ for (const key in obj)
52
+ obj.hasOwnProperty(key) && searchUsers(obj[key]);
53
+ } else Array.isArray(obj) && obj.forEach((item) => searchUsers(item));
54
+ };
55
+ return searchUsers(data), users;
56
+ }
57
+ function extractTweets(data) {
58
+ const tweets = [], tweetIds = /* @__PURE__ */ new Set();
59
+ data?.globalObjects?.tweets && Object.values(data.globalObjects.tweets).forEach((tweet) => {
60
+ tweet && tweet.id_str && !tweetIds.has(tweet.id_str) && (tweet.__typename = "Tweet", tweet.rest_id = tweet.id_str, tweetIds.add(tweet.id_str), tweets.push(tweet));
61
+ }), data?.data?.viewer_v2?.user_results?.result?.notification_timeline?.timeline?.instructions && data.data.viewer_v2.user_results.result.notification_timeline.timeline.instructions.forEach((instruction) => {
62
+ instruction.entries && instruction.entries.forEach((entry) => {
63
+ entry.content?.itemContent?.template?.target_objects && entry.content.itemContent.template.target_objects.forEach((targetObject) => {
64
+ if (targetObject?.tweet_results?.result) {
65
+ const tweet = targetObject.tweet_results.result;
66
+ tweet && tweet.rest_id && !tweetIds.has(tweet.rest_id) && (tweet.__typename = "Tweet", entry.entryId && (tweet.entryId = entry.entryId), entry.content.clientEventInfo && (tweet.clientEventInfo = entry.content.clientEventInfo), tweetIds.add(tweet.rest_id), tweets.push(tweet));
67
+ }
68
+ });
69
+ });
70
+ });
71
+ const searchTweets = (obj, entryId, clientEventInfo) => {
72
+ if (obj && typeof obj == "object") {
73
+ if (obj.entryId && (entryId = obj.entryId), obj.clientEventInfo && (clientEventInfo = obj.clientEventInfo), (obj.__typename === "Tweet" || !obj.__typename && obj.rest_id && obj.legacy?.full_text) && obj.rest_id && !tweetIds.has(obj.rest_id) && (obj.__typename = "Tweet", entryId && (obj.entryId = entryId), clientEventInfo && (obj.clientEventInfo = clientEventInfo), tweetIds.add(obj.rest_id), tweets.push(obj)), obj.__typename === "TweetWithVisibilityResults" && obj.tweet && obj.tweet.rest_id && !tweetIds.has(obj.tweet.rest_id)) {
74
+ const tweet = obj.tweet;
75
+ tweet.__typename = "Tweet", entryId && (tweet.entryId = entryId), clientEventInfo && (tweet.clientEventInfo = clientEventInfo), tweetIds.add(tweet.rest_id), tweets.push(tweet);
76
+ }
77
+ for (const key in obj)
78
+ obj.hasOwnProperty(key) && searchTweets(obj[key], entryId, clientEventInfo);
79
+ } else Array.isArray(obj) && obj.forEach((item) => searchTweets(item, entryId, clientEventInfo));
80
+ };
81
+ return searchTweets(data), tweets;
82
+ }
83
+ function extractCursors(data, result) {
84
+ const searchCursors = (obj) => {
85
+ if (obj && typeof obj == "object") {
86
+ obj.cursor_top && (result.cursor_top = obj.cursor_top), obj.cursor_bottom && (result.cursor_bottom = obj.cursor_bottom), obj.next_cursor && (result.next_cursor = obj.next_cursor), obj.next_cursor_str && (result.next_cursor_str = obj.next_cursor_str), obj.previous_cursor && (result.previous_cursor = obj.previous_cursor), obj.previous_cursor_str && (result.previous_cursor_str = obj.previous_cursor_str), obj.entryId && (obj.entryId.startsWith("cursor-top-") || obj.entryId.startsWith("cursor-bottom-")) && obj.content && obj.content.value && (obj.entryId.startsWith("cursor-top-") ? result.cursor_top = obj.content.value : result.cursor_bottom = obj.content.value);
87
+ for (const key in obj)
88
+ obj.hasOwnProperty(key) && searchCursors(obj[key]);
89
+ } else Array.isArray(obj) && obj.forEach((item) => searchCursors(item));
90
+ };
91
+ searchCursors(data);
92
+ }
93
+ function convertToSimpleUser(user) {
94
+ return {
95
+ rest_id: user.rest_id,
96
+ name: user.legacy?.name || user.name || user.core?.name || "",
97
+ screen_name: user.legacy?.screen_name || user.screen_name || user.core?.screen_name || "",
98
+ profile_image_url_https: user.legacy?.profile_image_url_https || user.profile_image_url_https || user.avatar?.image_url || "",
99
+ verified: user.legacy?.verified || user.verified || user.verification?.verified,
100
+ blue_verified: user.is_blue_verified,
101
+ followers_count: user.legacy?.followers_count || user.followers_count,
102
+ friends_count: user.legacy?.friends_count || user.friends_count,
103
+ statuses_count: user.legacy?.statuses_count || user.statuses_count,
104
+ description: user.legacy?.description || user.description || user.profile_bio?.description || null,
105
+ location: user.legacy?.location || (typeof user.location == "string" ? user.location : user.location?.location || null),
106
+ url: user.legacy?.url || user.url || null,
107
+ userLabelType: user.affiliates_highlighted_label?.label?.userLabelType,
108
+ verified_type: user.legacy?.verified_type || user.verified_type
109
+ };
110
+ }
111
+ function getVideoQuality(bitrate) {
112
+ return bitrate >= 25e5 ? "high" : bitrate >= 12e5 ? "medium" : "low";
113
+ }
114
+ function convertToSimpleTweet(tweet, user) {
115
+ const tweetData = tweet.legacy || tweet;
116
+ let tweetQuality;
117
+ tweet.visibility_results?.tweet_visibility_annotations ? tweetQuality = tweet.visibility_results.tweet_visibility_annotations.find(
118
+ (item) => item.tweet_quality
119
+ )?.tweet_quality : tweet.clientEventInfo?.details?.conversationDetails?.conversationSection && (tweetQuality = tweet.clientEventInfo?.details?.conversationDetails?.conversationSection), tweetQuality || (tweetQuality = "HighQuality");
120
+ const simpleTweet = {
121
+ rest_id: tweet.rest_id,
122
+ full_text: tweetData.full_text || "",
123
+ created_at: tweetData.created_at || "",
124
+ user: user ? convertToSimpleUser(user) : {
125
+ rest_id: tweetData.user_id_str || "",
126
+ name: "",
127
+ screen_name: "",
128
+ profile_image_url_https: ""
129
+ },
130
+ retweet_count: tweetData.retweet_count,
131
+ favorite_count: tweetData.favorite_count,
132
+ reply_count: tweetData.reply_count,
133
+ quote_count: tweetData.quote_count,
134
+ lang: tweetData.lang,
135
+ conversation_id: tweetData.conversation_id_str || "",
136
+ possibly_sensitive: tweetData.possibly_sensitive,
137
+ is_retweet: !!tweetData.retweeted_status_id_str,
138
+ retweeted_status_id: tweetData.retweeted_status_id_str,
139
+ quoted_status_id: tweetData.quoted_status_id_str,
140
+ quality: tweetQuality
141
+ }, media = tweetData.extended_entities?.media || tweetData.entities?.media;
142
+ if (media) {
143
+ const photos = [], videos = [], gifs = [];
144
+ media.forEach((mediaItem) => {
145
+ if (mediaItem.type === "photo") {
146
+ let simpleSizes;
147
+ mediaItem.sizes && (simpleSizes = {}, mediaItem.sizes.thumb && (simpleSizes.thumb = {
148
+ w: mediaItem.sizes.thumb.w || 0,
149
+ h: mediaItem.sizes.thumb.h || 0,
150
+ resize: mediaItem.sizes.thumb.resize || "fit"
151
+ }), mediaItem.sizes.small && (simpleSizes.small = {
152
+ w: mediaItem.sizes.small.w || 0,
153
+ h: mediaItem.sizes.small.h || 0,
154
+ resize: mediaItem.sizes.small.resize || "fit"
155
+ }), mediaItem.sizes.medium && (simpleSizes.medium = {
156
+ w: mediaItem.sizes.medium.w || 0,
157
+ h: mediaItem.sizes.medium.h || 0,
158
+ resize: mediaItem.sizes.medium.resize || "fit"
159
+ }), mediaItem.sizes.large && (simpleSizes.large = {
160
+ w: mediaItem.sizes.large.w || 0,
161
+ h: mediaItem.sizes.large.h || 0,
162
+ resize: mediaItem.sizes.large.resize || "fit"
163
+ }));
164
+ let simpleOriginalInfo;
165
+ mediaItem.original_info && (simpleOriginalInfo = {
166
+ width: mediaItem.original_info.width || 0,
167
+ height: mediaItem.original_info.height || 0
168
+ }), photos.push({
169
+ media_key: mediaItem.media_key || "",
170
+ type: "photo",
171
+ media_url_https: mediaItem.media_url_https || "",
172
+ display_url: mediaItem.display_url || "",
173
+ expanded_url: mediaItem.expanded_url || "",
174
+ sizes: simpleSizes,
175
+ original_info: simpleOriginalInfo
176
+ });
177
+ } else if (mediaItem.type === "video") {
178
+ const mp4Videos = mediaItem.video_info?.variants?.filter(
179
+ (item) => item?.content_type === "video/mp4"
180
+ ).map((variant) => ({
181
+ bitrate: variant.bitrate,
182
+ url: variant.url || "",
183
+ quality: variant.bitrate ? getVideoQuality(variant.bitrate) : void 0
184
+ })), hlsVideo = mediaItem.video_info?.variants?.find((item) => item?.content_type === "application/x-mpegURL");
185
+ videos.push({
186
+ media_key: mediaItem.media_key || "",
187
+ type: "video",
188
+ media_url_https: mediaItem.media_url_https || "",
189
+ display_url: mediaItem.display_url || "",
190
+ expanded_url: mediaItem.expanded_url || "",
191
+ aspect_ratio: mediaItem.video_info?.aspect_ratio,
192
+ duration_millis: mediaItem.video_info?.duration_millis,
193
+ mp4: mp4Videos,
194
+ hls: hlsVideo?.url
195
+ });
196
+ } else if (mediaItem.type === "animated_gif") {
197
+ const mp4Video = mediaItem.video_info?.variants?.find((item) => item?.content_type === "video/mp4");
198
+ gifs.push({
199
+ media_key: mediaItem.media_key || "",
200
+ type: "animated_gif",
201
+ media_url_https: mediaItem.media_url_https || "",
202
+ display_url: mediaItem.display_url || "",
203
+ expanded_url: mediaItem.expanded_url || "",
204
+ aspect_ratio: mediaItem.video_info?.aspect_ratio,
205
+ duration_millis: mediaItem.video_info?.duration_millis,
206
+ mp4: mp4Video?.url
207
+ });
208
+ }
209
+ }), photos.length > 0 && (simpleTweet.photos = photos), videos.length > 0 && (simpleTweet.videos = videos), gifs.length > 0 && (simpleTweet.gifs = gifs);
210
+ }
211
+ if (tweetData.entities?.urls) {
212
+ const urls = tweetData.entities.urls.map((url) => ({
213
+ url: url.url || "",
214
+ expanded_url: url.expanded_url || "",
215
+ display_url: url.display_url || ""
216
+ }));
217
+ urls.length > 0 && (simpleTweet.urls = urls);
218
+ }
219
+ return simpleTweet;
220
+ }
1
221
  class XParser {
2
222
  /**
3
223
  * 解析任意对象为ISimpleResult
4
224
  * @param data 任意对象
225
+ * @param options 解析选项
5
226
  * @returns ISimpleResult
6
227
  */
7
- static parseSimple(data) {
8
- const result = {}, users = this.#extractUsers(data);
9
- users.length > 0 && (result.users = users.map((user) => this.convertToSimpleUser(user)));
10
- const tweets = this.#extractTweets(data);
11
- return tweets.length > 0 && (result.tweets = tweets.map((tweet) => this.convertToSimpleTweet(tweet)), result.photos = result.tweets.filter((tweet) => tweet.photos && tweet.photos.length > 0), result.videos = result.tweets.filter((tweet) => tweet.videos && tweet.videos.length > 0), result.urls = result.tweets.filter((tweet) => tweet.urls && tweet.urls.length > 0)), this.#extractCursors(data, result), result;
228
+ static parseSimple(data, options = {}) {
229
+ const result = {
230
+ users: [],
231
+ tweets: [],
232
+ ads: [],
233
+ exploreMore: [],
234
+ recommendations: [],
235
+ photos: [],
236
+ videos: [],
237
+ urls: []
238
+ }, users = extractUsers(data), tweets = extractTweets(data), userMap = /* @__PURE__ */ new Map();
239
+ if (users.forEach((user) => {
240
+ userMap.set(user.rest_id, user);
241
+ }), result.users = users.map((user) => convertToSimpleUser(user)), tweets.length > 0) {
242
+ const allTweets = tweets.map((tweet) => {
243
+ const userId = tweet.legacy?.user_id_str || tweet.user_id_str, user = userMap.get(userId || "");
244
+ return convertToSimpleTweet(tweet, user);
245
+ }), { tweets: filteredTweets, ads, exploreMore, recommendations } = filterTweets(allTweets, tweets, options);
246
+ result.tweets = filteredTweets, result.ads = ads, result.exploreMore = exploreMore, result.recommendations = recommendations, result.photos = result.tweets.filter((tweet) => tweet.photos && tweet.photos.length > 0), result.videos = result.tweets.filter((tweet) => tweet.videos && tweet.videos.length > 0), result.gifs = result.tweets.filter((tweet) => tweet.gifs && tweet.gifs.length > 0), result.urls = result.tweets.filter((tweet) => tweet.urls && tweet.urls.length > 0);
247
+ }
248
+ return extractCursors(data, result), result;
12
249
  }
13
250
  /**
14
251
  * 解析任意对象为IOriginalResult
15
252
  * @param data 任意对象
253
+ * @param options 解析选项
16
254
  * @returns IOriginalResult
17
255
  */
18
- static parseOriginal(data) {
19
- const result = {}, users = this.#extractUsers(data);
20
- users.length > 0 && (result.users = users);
21
- const tweets = this.#extractTweets(data);
22
- return tweets.length > 0 && (result.tweets = tweets, result.photos = result.tweets.filter((tweet) => {
23
- const legacy = tweet.legacy;
24
- return legacy && legacy.extended_entities && legacy.extended_entities.media && legacy.extended_entities.media.some((media) => media.type === "photo");
25
- }), result.videos = result.tweets.filter((tweet) => {
26
- const legacy = tweet.legacy;
27
- return legacy && legacy.extended_entities && legacy.extended_entities.media && legacy.extended_entities.media.some((media) => media.type === "video" || media.type === "animated_gif");
28
- }), result.urls = result.tweets.filter((tweet) => {
29
- const legacy = tweet.legacy;
30
- return legacy && legacy.entities && legacy.entities.urls && legacy.entities.urls.length > 0;
31
- })), this.#extractCursors(data, result), result;
32
- }
33
- /**
34
- * 将IUser转换为ISimpleUser
35
- * @param user IUser对象
36
- * @returns ISimpleUser
37
- */
38
- static convertToSimpleUser(user) {
39
- return {
40
- rest_id: user.rest_id,
41
- name: user.legacy?.name || "",
42
- screen_name: user.legacy?.screen_name || "",
43
- profile_image_url_https: user.legacy?.profile_image_url_https || "",
44
- verified: user.legacy?.verified,
45
- followers_count: user.legacy?.followers_count,
46
- friends_count: user.legacy?.friends_count,
47
- statuses_count: user.legacy?.statuses_count,
48
- description: user.legacy?.description,
49
- location: user.legacy?.location,
50
- url: user.legacy?.url,
51
- userLabelType: user.affiliates_highlighted_label?.label?.userLabelType,
52
- verified_type: user.legacy?.verified_type
53
- };
54
- }
55
- /**
56
- * 将ITweet转换为ISimpleTweet
57
- * @param tweet ITweet对象
58
- * @returns ISimpleTweet
59
- */
60
- static convertToSimpleTweet(tweet) {
61
- const legacy = tweet.legacy, simpleTweet = {
62
- rest_id: tweet.rest_id,
63
- full_text: legacy?.full_text || "",
64
- created_at: legacy?.created_at || "",
65
- user_id: legacy?.user_id_str || "",
66
- user_screen_name: "",
67
- // 需要从用户信息中获取
68
- retweet_count: legacy?.retweet_count,
69
- favorite_count: legacy?.favorite_count,
70
- reply_count: legacy?.reply_count,
71
- quote_count: legacy?.quote_count,
72
- lang: legacy?.lang,
73
- conversation_id: legacy?.conversation_id_str,
74
- possibly_sensitive: legacy?.possibly_sensitive,
75
- is_retweet: !!legacy?.retweeted_status_id_str,
76
- retweeted_status_id: legacy?.retweeted_status_id_str,
77
- quoted_status_id: legacy?.quoted_status_id_str
78
- };
79
- if (legacy?.extended_entities?.media) {
80
- const photos = [], videos = [];
81
- legacy.extended_entities.media.forEach((media) => {
82
- if (media.type === "photo") {
83
- let simpleSizes;
84
- media.sizes && (simpleSizes = {}, media.sizes.thumb && (simpleSizes.thumb = {
85
- w: media.sizes.thumb.w || 0,
86
- h: media.sizes.thumb.h || 0,
87
- resize: media.sizes.thumb.resize || "fit"
88
- }), media.sizes.small && (simpleSizes.small = {
89
- w: media.sizes.small.w || 0,
90
- h: media.sizes.small.h || 0,
91
- resize: media.sizes.small.resize || "fit"
92
- }), media.sizes.medium && (simpleSizes.medium = {
93
- w: media.sizes.medium.w || 0,
94
- h: media.sizes.medium.h || 0,
95
- resize: media.sizes.medium.resize || "fit"
96
- }), media.sizes.large && (simpleSizes.large = {
97
- w: media.sizes.large.w || 0,
98
- h: media.sizes.large.h || 0,
99
- resize: media.sizes.large.resize || "fit"
100
- }));
101
- let simpleOriginalInfo;
102
- media.original_info && (simpleOriginalInfo = {
103
- width: media.original_info.width || 0,
104
- height: media.original_info.height || 0
105
- }), photos.push({
106
- media_key: media.media_key || "",
107
- type: "photo",
108
- media_url_https: media.media_url_https || "",
109
- display_url: media.display_url || "",
110
- expanded_url: media.expanded_url || "",
111
- sizes: simpleSizes,
112
- original_info: simpleOriginalInfo
113
- });
114
- } else if (media.type === "video" || media.type === "animated_gif") {
115
- let simpleVideoInfo;
116
- media.video_info && (simpleVideoInfo = {
117
- aspect_ratio: media.video_info.aspect_ratio,
118
- duration_millis: media.video_info.duration_millis,
119
- variants: media.video_info.variants?.map((variant) => ({
120
- bitrate: variant.bitrate,
121
- content_type: variant.content_type || "",
122
- url: variant.url || ""
123
- }))
124
- }), videos.push({
125
- media_key: media.media_key || "",
126
- type: media.type,
127
- media_url_https: media.media_url_https || "",
128
- display_url: media.display_url || "",
129
- expanded_url: media.expanded_url || "",
130
- video_info: simpleVideoInfo
131
- });
132
- }
133
- }), photos.length > 0 && (simpleTweet.photos = photos), videos.length > 0 && (simpleTweet.videos = videos);
134
- }
135
- if (legacy?.entities?.urls) {
136
- const urls = legacy.entities.urls.map((url) => ({
137
- url: url.url || "",
138
- expanded_url: url.expanded_url || "",
139
- display_url: url.display_url || ""
140
- }));
141
- urls.length > 0 && (simpleTweet.urls = urls);
256
+ static parseOriginal(data, options = {}) {
257
+ const result = {
258
+ users: [],
259
+ tweets: [],
260
+ ads: [],
261
+ exploreMore: [],
262
+ recommendations: [],
263
+ photos: [],
264
+ videos: [],
265
+ urls: []
266
+ }, users = extractUsers(data), tweets = extractTweets(data);
267
+ if (result.users = users, tweets.length > 0) {
268
+ const { tweets: filteredTweets, ads, exploreMore, recommendations } = filterTweets(tweets, tweets, options);
269
+ result.tweets = filteredTweets, result.ads = ads, result.exploreMore = exploreMore, result.recommendations = recommendations, result.photos = result.tweets.filter((tweet) => {
270
+ const legacy = tweet.legacy;
271
+ return legacy && legacy.extended_entities && legacy.extended_entities.media && legacy.extended_entities.media.some((media) => media.type === "photo");
272
+ }), result.videos = result.tweets.filter((tweet) => {
273
+ const legacy = tweet.legacy;
274
+ return legacy && legacy.extended_entities && legacy.extended_entities.media && legacy.extended_entities.media.some((media) => media.type === "video");
275
+ }), result.gifs = result.tweets.filter((tweet) => {
276
+ const legacy = tweet.legacy;
277
+ return legacy && legacy.extended_entities && legacy.extended_entities.media && legacy.extended_entities.media.some((media) => media.type === "animated_gif");
278
+ }), result.urls = result.tweets.filter((tweet) => {
279
+ const legacy = tweet.legacy;
280
+ return legacy && legacy.entities && legacy.entities.urls && legacy.entities.urls.length > 0;
281
+ });
142
282
  }
143
- return simpleTweet;
144
- }
145
- /**
146
- * 从数据中提取用户
147
- * @param data 任意对象
148
- * @returns IUser数组
149
- */
150
- static #extractUsers(data) {
151
- const users = [], searchUsers = (obj) => {
152
- if (obj && typeof obj == "object") {
153
- obj.__typename === "User" && obj.rest_id && users.push(obj);
154
- for (const key in obj)
155
- obj.hasOwnProperty(key) && searchUsers(obj[key]);
156
- } else Array.isArray(obj) && obj.forEach((item) => searchUsers(item));
157
- };
158
- return searchUsers(data), users;
159
- }
160
- /**
161
- * 从数据中提取推文
162
- * @param data 任意对象
163
- * @returns ITweet数组
164
- */
165
- static #extractTweets(data) {
166
- const tweets = [], searchTweets = (obj) => {
167
- if (obj && typeof obj == "object") {
168
- obj.__typename === "Tweet" && obj.rest_id && tweets.push(obj);
169
- for (const key in obj)
170
- obj.hasOwnProperty(key) && searchTweets(obj[key]);
171
- } else Array.isArray(obj) && obj.forEach((item) => searchTweets(item));
172
- };
173
- return searchTweets(data), tweets;
174
- }
175
- /**
176
- * 从数据中提取游标
177
- * @param data 任意对象
178
- * @param result 结果对象
179
- */
180
- static #extractCursors(data, result) {
181
- const searchCursors = (obj) => {
182
- if (obj && typeof obj == "object") {
183
- obj.cursor_top && (result.cursor_top = obj.cursor_top), obj.cursor_bottom && (result.cursor_bottom = obj.cursor_bottom), obj.next_cursor && (result.next_cursor = obj.next_cursor), obj.next_cursor_str && (result.next_cursor_str = obj.next_cursor_str), obj.previous_cursor && (result.previous_cursor = obj.previous_cursor), obj.previous_cursor_str && (result.previous_cursor_str = obj.previous_cursor_str), obj.entryId && (obj.entryId.startsWith("cursor-top-") || obj.entryId.startsWith("cursor-bottom-")) && (obj.entryId.startsWith("cursor-top-") ? result.cursor_top = obj.entryId.replace("cursor-top-", "") : result.cursor_bottom = obj.entryId.replace("cursor-bottom-", ""));
184
- for (const key in obj)
185
- obj.hasOwnProperty(key) && searchCursors(obj[key]);
186
- } else Array.isArray(obj) && obj.forEach((item) => searchCursors(item));
187
- };
188
- searchCursors(data);
283
+ return extractCursors(data, result), result;
189
284
  }
190
285
  }
191
286
  export {
package/lib/type.cjs CHANGED
@@ -1,4 +1,4 @@
1
1
  "use strict";
2
- const USER_TYPENAMES = ["User", "UserUnavailable"], TWEET_TYPENAMES = ["Tweet", "TextTombstone", "TweetTombstone", "TweetWithVisibilityResults", "ContextualTweetInterstitial"], COMMUNITY_TYPENAMES = ["Community", "CommunityDeleteActionUnavailable", "CommunityUserDefaultModerationState", "CommunityJoinRequestsUnavailable"], TIMELINE_TYPENAMES = ["TimelineTimelineItem", "TimelineMessagePrompt"], TIMELINE_ITEM_TYPENAMES = ["TimelineTweet", "TimelineMessagePrompt"], TIMELINE_INSTRUCTION_TYPES = ["TimelineAddEntries"], TIMELINE_ENTRY_TYPES = ["TimelineTimelineItem", "TimelineTimelineModule", "TimelineTimelineCursor"], TIMELINE_ITEM_TYPES = ["TimelineTweet", "TimelineMessagePrompt"], MEDIA_TYPES = ["photo", "video", "animated_gif"], ELIGIBILITY_TYPES = ["Eligible", "IneligibleUserUnauthorized"], DISPLAY_TYPES = ["Carousel", "Vertical", "VerticalConversation", "Classic", "EntireTweet"], TWEET_DISPLAY_TYPES = ["CondensedTweet", "Tweet", "SelfThread"], USER_DISPLAY_TYPES = ["SubscribableUser", "User"], INJECTION_TYPES = ["ForYouInNetwork", "ForYouPromoted", "WhoToFollow", "creators-only-connect-tab", "CommunityToJoin"], TRANSPARENT_GUIDE_DETAIL_TYPES = ["TimelineEventUrtMetadata"], ELEMENT_TYPES = ["tweet", "user", "event", "feedback", "trend", "users_followed_you", "generic_report_received", "users_liked_your_tweet", "user_quoted_your_tweet", "user_replied_to_your_tweet", "users_retweeted_your_tweet", "user_mentioned_you"], TWEET_QUALITIES = ["HighQuality", "LowQuality", "AbusiveQuality", "RelatedTweet"], COMPONENT_VALUES = ["url", "tweet", "trends", "unified_events", "related_tweet", "suggest_who_to_follow", "for_you_in_network", "for-you-promoted", "alt-text-prompt-injection", "ads-sharing-x-premium-upsell-candidate"], ITEM_TYPES = ["TimelineTweet", "TimelineUser", "TimelineEventSummary", "TimelineMessagePrompt", "TimelineCommunity", "CommunityPinnedTimeline"], CURSOR_TYPES = ["Top", "Bottom", "ShowMore", "ShowMoreThreads"], INSTRUCTION_TYPES = ["TimelineClearCache", "TimelineAddEntries", "TimelineTerminateTimeline", "TimelineShowAlert", "TimelineShowCover"], CONTENT_TYPES = ["TimelineTweetMedia", "TimelineUrl"], VIDEO_CONTENT_TYPES = ["application/x-mpegURL", "video/mp4"], MESSAGE_INBOX_TIMELINE_INDEXES = ["trusted", "untrusted", "untrusted_low_quality"], NOTIFICATION_KEYS = ["clearCache", "addEntries", "clearEntriesUnreadState", "markEntriesUnreadGreaterThanSortIndex"], VERIFIED_TYPES = ["Business", "Government", "Blue", "None"], USER_LABEL_TYPES = ["BusinessLabel", "AutomatedLabel"], URL_TYPES = ["ExternalUrl", "DeepLink", "UrtEndpoint"], VIEW_STATES = ["EnabledWithCount", "Enabled"], LEGACY_CARD_BINDING_KEY_TYPES = ["thumbnail_image", "description", "domain", "thumbnail_image_large", "thumbnail_image_original", "thumbnail_image_small", "thumbnail_image_x_large", "thumbnail_image_color", "summary_photo_image", "summary_photo_image_small", "summary_photo_image_large", "summary_photo_image_x_large", "summary_photo_image_original", "summary_photo_image_color", "photo_image_full_size_color", "vanity_url", "title", "card_url", "creator", "site", "player_image", "player_image_small", "player_image_large", "player_image_x_large", "player_image_original", "player_image_color", "player_url", "player_width", "player_height", "app_name", "app_is_free", "app_star_rating", "app_num_ratings", "app_price_currency", "unified_card", "app_price_amount"], LEGACY_CARD_BINDING_VALUE_TYPES = ["STRING", "IMAGE_COLOR", "IMAGE", "USER"];
2
+ const USER_TYPENAMES = ["User", "UserUnavailable"], TWEET_TYPENAMES = ["Tweet", "TextTombstone", "TweetTombstone", "TweetWithVisibilityResults", "ContextualTweetInterstitial"], COMMUNITY_TYPENAMES = ["Community", "CommunityDeleteActionUnavailable", "CommunityUserDefaultModerationState", "CommunityJoinRequestsUnavailable"], TIMELINE_TYPENAMES = ["TimelineTimelineItem", "TimelineMessagePrompt"], TIMELINE_ITEM_TYPENAMES = ["TimelineTweet", "TimelineMessagePrompt"], TIMELINE_INSTRUCTION_TYPES = ["TimelineAddEntries"], TIMELINE_ENTRY_TYPES = ["TimelineTimelineItem", "TimelineTimelineModule", "TimelineTimelineCursor"], TIMELINE_ITEM_TYPES = ["TimelineTweet", "TimelineMessagePrompt"], MEDIA_TYPES = ["photo", "video", "animated_gif"], ELIGIBILITY_TYPES = ["Eligible", "IneligibleUserUnauthorized"], DISPLAY_TYPES = ["Carousel", "Vertical", "VerticalConversation", "Classic", "EntireTweet"], TWEET_DISPLAY_TYPES = ["CondensedTweet", "Tweet", "SelfThread"], USER_DISPLAY_TYPES = ["SubscribableUser", "User"], INJECTION_TYPES = ["ForYouInNetwork", "ForYouPromoted", "WhoToFollow", "creators-only-connect-tab", "CommunityToJoin", "FollowingInNetwork"], TRANSPARENT_GUIDE_DETAIL_TYPES = ["TimelineEventUrtMetadata"], ELEMENT_TYPES = ["tweet", "user", "event", "feedback", "trend", "users_followed_you", "generic_report_received", "users_liked_your_tweet", "user_quoted_your_tweet", "user_replied_to_your_tweet", "users_retweeted_your_tweet", "user_mentioned_you"], TWEET_QUALITIES = ["HighQuality", "LowQuality", "AbusiveQuality", "RelatedTweet"], COMPONENT_VALUES = ["url", "tweet", "trends", "unified_events", "related_tweet", "suggest_who_to_follow", "for_you_in_network", "for-you-promoted", "alt-text-prompt-injection", "ads-sharing-x-premium-upsell-candidate"], ITEM_TYPES = ["TimelineTweet", "TimelineUser", "TimelineEventSummary", "TimelineMessagePrompt", "TimelineCommunity", "CommunityPinnedTimeline"], CURSOR_TYPES = ["Top", "Bottom", "ShowMore", "ShowMoreThreads"], INSTRUCTION_TYPES = ["TimelineClearCache", "TimelineAddEntries", "TimelineTerminateTimeline", "TimelineShowAlert", "TimelineShowCover"], CONTENT_TYPES = ["TimelineTweetMedia", "TimelineUrl"], VIDEO_CONTENT_TYPES = ["application/x-mpegURL", "video/mp4"], VIDEO_QUALITIES = ["high", "medium", "low"], MESSAGE_INBOX_TIMELINE_INDEXES = ["trusted", "untrusted", "untrusted_low_quality"], NOTIFICATION_KEYS = ["clearCache", "addEntries", "clearEntriesUnreadState", "markEntriesUnreadGreaterThanSortIndex"], VERIFIED_TYPES = ["Business", "Government", "Blue", "None"], USER_LABEL_TYPES = ["BusinessLabel", "AutomatedLabel"], URL_TYPES = ["ExternalUrl", "DeepLink", "UrtEndpoint"], VIEW_STATES = ["EnabledWithCount", "Enabled"], LEGACY_CARD_BINDING_KEY_TYPES = ["thumbnail_image", "description", "domain", "thumbnail_image_large", "thumbnail_image_original", "thumbnail_image_small", "thumbnail_image_x_large", "thumbnail_image_color", "summary_photo_image", "summary_photo_image_small", "summary_photo_image_large", "summary_photo_image_x_large", "summary_photo_image_original", "summary_photo_image_color", "photo_image_full_size_color", "vanity_url", "title", "card_url", "creator", "site", "player_image", "player_image_small", "player_image_large", "player_image_x_large", "player_image_original", "player_image_color", "player_url", "player_width", "player_height", "app_name", "app_is_free", "app_star_rating", "app_num_ratings", "app_price_currency", "unified_card", "app_price_amount"], LEGACY_CARD_BINDING_VALUE_TYPES = ["STRING", "IMAGE_COLOR", "IMAGE", "USER"];
3
3
  var IdPrefixes = /* @__PURE__ */ ((IdPrefixes2) => (IdPrefixes2.MessagePrompt = "messageprompt-", IdPrefixes2.NormalTweet = "tweet-", IdPrefixes2.PromotedTweet = "promoted-tweet-", IdPrefixes2.User = "user-", IdPrefixes2.CommunityToJoin = "community-to-join-", IdPrefixes2.HomeConversation = "home-conversation-", IdPrefixes2.Conversationthread = "conversationthread-", IdPrefixes2.CommunityConversation = "community-conversation-", IdPrefixes2.CommunityGrid = "communities-grid-", IdPrefixes2.PinnedTweets = "pinned-tweets-", IdPrefixes2.WhoToFollow = "who-to-follow-", IdPrefixes2.CreatorsOnlyConnectTab = "creators-only-connect-tab-", IdPrefixes2.Label = "label-", IdPrefixes2.Guide = "Guide-", IdPrefixes2.ProfileGrid = "profile-grid-", IdPrefixes2.Notification = "notification-", IdPrefixes2.Cursor = "cursor-", IdPrefixes2.CursorTop = "cursor-top-", IdPrefixes2.CursorBottom = "cursor-bottom-", IdPrefixes2.TweetDetailRelatedTweets = "tweetdetailrelatedtweets-", IdPrefixes2.Trends = "trends-", IdPrefixes2))(IdPrefixes || {});
4
- exports.COMMUNITY_TYPENAMES = COMMUNITY_TYPENAMES, exports.COMPONENT_VALUES = COMPONENT_VALUES, exports.CONTENT_TYPES = CONTENT_TYPES, exports.CURSOR_TYPES = CURSOR_TYPES, exports.DISPLAY_TYPES = DISPLAY_TYPES, exports.ELEMENT_TYPES = ELEMENT_TYPES, exports.ELIGIBILITY_TYPES = ELIGIBILITY_TYPES, exports.INJECTION_TYPES = INJECTION_TYPES, exports.INSTRUCTION_TYPES = INSTRUCTION_TYPES, exports.ITEM_TYPES = ITEM_TYPES, exports.IdPrefixes = IdPrefixes, exports.LEGACY_CARD_BINDING_KEY_TYPES = LEGACY_CARD_BINDING_KEY_TYPES, exports.LEGACY_CARD_BINDING_VALUE_TYPES = LEGACY_CARD_BINDING_VALUE_TYPES, exports.MEDIA_TYPES = MEDIA_TYPES, exports.MESSAGE_INBOX_TIMELINE_INDEXES = MESSAGE_INBOX_TIMELINE_INDEXES, exports.NOTIFICATION_KEYS = NOTIFICATION_KEYS, exports.TIMELINE_ENTRY_TYPES = TIMELINE_ENTRY_TYPES, exports.TIMELINE_INSTRUCTION_TYPES = TIMELINE_INSTRUCTION_TYPES, exports.TIMELINE_ITEM_TYPENAMES = TIMELINE_ITEM_TYPENAMES, exports.TIMELINE_ITEM_TYPES = TIMELINE_ITEM_TYPES, exports.TIMELINE_TYPENAMES = TIMELINE_TYPENAMES, exports.TRANSPARENT_GUIDE_DETAIL_TYPES = TRANSPARENT_GUIDE_DETAIL_TYPES, exports.TWEET_DISPLAY_TYPES = TWEET_DISPLAY_TYPES, exports.TWEET_QUALITIES = TWEET_QUALITIES, exports.TWEET_TYPENAMES = TWEET_TYPENAMES, exports.URL_TYPES = URL_TYPES, exports.USER_DISPLAY_TYPES = USER_DISPLAY_TYPES, exports.USER_LABEL_TYPES = USER_LABEL_TYPES, exports.USER_TYPENAMES = USER_TYPENAMES, exports.VERIFIED_TYPES = VERIFIED_TYPES, exports.VIDEO_CONTENT_TYPES = VIDEO_CONTENT_TYPES, exports.VIEW_STATES = VIEW_STATES;
4
+ exports.COMMUNITY_TYPENAMES = COMMUNITY_TYPENAMES, exports.COMPONENT_VALUES = COMPONENT_VALUES, exports.CONTENT_TYPES = CONTENT_TYPES, exports.CURSOR_TYPES = CURSOR_TYPES, exports.DISPLAY_TYPES = DISPLAY_TYPES, exports.ELEMENT_TYPES = ELEMENT_TYPES, exports.ELIGIBILITY_TYPES = ELIGIBILITY_TYPES, exports.INJECTION_TYPES = INJECTION_TYPES, exports.INSTRUCTION_TYPES = INSTRUCTION_TYPES, exports.ITEM_TYPES = ITEM_TYPES, exports.IdPrefixes = IdPrefixes, exports.LEGACY_CARD_BINDING_KEY_TYPES = LEGACY_CARD_BINDING_KEY_TYPES, exports.LEGACY_CARD_BINDING_VALUE_TYPES = LEGACY_CARD_BINDING_VALUE_TYPES, exports.MEDIA_TYPES = MEDIA_TYPES, exports.MESSAGE_INBOX_TIMELINE_INDEXES = MESSAGE_INBOX_TIMELINE_INDEXES, exports.NOTIFICATION_KEYS = NOTIFICATION_KEYS, exports.TIMELINE_ENTRY_TYPES = TIMELINE_ENTRY_TYPES, exports.TIMELINE_INSTRUCTION_TYPES = TIMELINE_INSTRUCTION_TYPES, exports.TIMELINE_ITEM_TYPENAMES = TIMELINE_ITEM_TYPENAMES, exports.TIMELINE_ITEM_TYPES = TIMELINE_ITEM_TYPES, exports.TIMELINE_TYPENAMES = TIMELINE_TYPENAMES, exports.TRANSPARENT_GUIDE_DETAIL_TYPES = TRANSPARENT_GUIDE_DETAIL_TYPES, exports.TWEET_DISPLAY_TYPES = TWEET_DISPLAY_TYPES, exports.TWEET_QUALITIES = TWEET_QUALITIES, exports.TWEET_TYPENAMES = TWEET_TYPENAMES, exports.URL_TYPES = URL_TYPES, exports.USER_DISPLAY_TYPES = USER_DISPLAY_TYPES, exports.USER_LABEL_TYPES = USER_LABEL_TYPES, exports.USER_TYPENAMES = USER_TYPENAMES, exports.VERIFIED_TYPES = VERIFIED_TYPES, exports.VIDEO_CONTENT_TYPES = VIDEO_CONTENT_TYPES, exports.VIDEO_QUALITIES = VIDEO_QUALITIES, exports.VIEW_STATES = VIEW_STATES;