feat(route): Twitter用户时间线和用户媒体时间线不再需要开发者账户 (#7739)

This commit is contained in:
Howard Yin
2021-10-05 17:40:31 +08:00
committed by GitHub
parent e09393e15d
commit 8875fb127f
16 changed files with 418 additions and 95 deletions

View File

@@ -0,0 +1,123 @@
const twitterGot = require('./twitter-got');
const _params = {
count: 20,
include_profile_interstitial_type: 1,
include_blocking: 1,
include_blocked_by: 1,
include_followed_by: 1,
include_want_retweets: 1,
include_mute_edge: 1,
include_can_dm: 1,
include_can_media_tag: 1,
skip_status: 1,
cards_platform: 'Web-12',
include_cards: 1,
include_ext_alt_text: true,
include_quote_count: true,
include_reply_count: 1,
tweet_mode: 'extended',
include_entities: true,
include_user_entities: true,
include_ext_media_color: true,
include_ext_media_availability: true,
send_error_codes: true,
simple_quoted_tweet: true,
include_tweet_replies: false,
ext: 'mediaStats,highlightedLabel',
};
const pagination = (endpoint, userId, params) =>
twitterGot('https://api.twitter.com' + endpoint, {
..._params,
...params,
userId,
});
const timelineMedia = (userId, params = {}) => pagination(`/2/timeline/media/${userId}.json`, userId, params);
const timelineTweets = (userId, params = {}) => pagination(`/2/timeline/profile/${userId}.json`, userId, params);
const timelineTweetsAndReplies = (userId, params = {}) =>
pagination(`/2/timeline/profile/${userId}.json`, userId, {
...params,
include_tweet_replies: true,
});
const timelineLikes = (userId, params = {}) =>
pagination(`/2/timeline/favorites/${userId}.json`, userId, {
...params,
sorted_by_time: true,
});
const timelineKeywords = (keywords, params = {}) =>
twitterGot('https://twitter.com/i/api/2/search/adaptive.json', {
..._params,
...params,
q: keywords,
query_source: 'typed_query',
pc: 1,
});
function pickLegacyByID(id, tweets_dict, users_dict) {
function pickLegacyFromTweet(tweet) {
tweet.user = users_dict[tweet.user_id_str];
if (tweet.retweeted_status_id_str) {
tweet.retweeted_status = pickLegacyFromTweet(tweets_dict[tweet.retweeted_status_id_str]);
}
return tweet;
}
if (tweets_dict[id]) {
return pickLegacyFromTweet(tweets_dict[id]);
}
}
function gatherLegacyFromData(data, filter = 'tweet-') {
const tweets_dict = data.globalObjects.tweets;
const users_dict = data.globalObjects.users;
const tweets = [];
data.timeline.instructions[0].addEntries.entries.forEach((entry) => {
if (entry.entryId && entry.entryId.indexOf(filter) !== -1) {
const tweet = pickLegacyByID(entry.content.item.content.tweet.id, tweets_dict, users_dict);
if (tweet) {
tweets.push(tweet);
}
}
});
return tweets;
}
const getUserTweetsByID = async (id, params = {}) => gatherLegacyFromData(await timelineTweets(id, params));
const getUserTweetsAndRepliesByID = async (id, params = {}) => gatherLegacyFromData(await timelineTweetsAndReplies(id, params));
const getUserMediaByID = async (id, params = {}) => gatherLegacyFromData(await timelineMedia(id, params));
const getUserLikesByID = async (id, params = {}) => gatherLegacyFromData(await timelineLikes(id, params));
const excludeRetweet = function (tweets) {
const excluded = [];
for (const t of tweets) {
if (t.retweeted_status) {
continue;
}
excluded.push(t);
}
return excluded;
};
const userByScreenName = (screenName) =>
twitterGot('https://twitter.com/i/api/graphql/hc-pka9A7gyS3xODIafnrQ/UserByScreenName', {
variables: `{"screen_name":"${screenName}","withHighlightedLabel":true}`,
});
const getUserData = (cache, screenName) => cache.tryGet(`twitter-userdata-${screenName}`, () => userByScreenName(screenName));
const getUserID = async (cache, screenName) => (await getUserData(cache, screenName)).data.user.rest_id;
const getUser = async (cache, screenName) => (await getUserData(cache, screenName)).data.user.legacy;
const getUserTweets = async (cache, screenName, params = {}) => getUserTweetsByID(await getUserID(cache, screenName), params);
const getUserTweetsAndReplies = async (cache, screenName, params = {}) => getUserTweetsAndRepliesByID(await getUserID(cache, screenName), params);
const getUserMedia = async (cache, screenName, params = {}) => getUserMediaByID(await getUserID(cache, screenName), params);
const getUserLikes = async (cache, screenName, params = {}) => getUserLikesByID(await getUserID(cache, screenName), params);
const getSearch = async (keywords, params = {}) => gatherLegacyFromData(await timelineKeywords(keywords, params), 'sq-I-t-');
module.exports = {
getUser,
getUserTweets,
getUserTweetsAndReplies,
getUserMedia,
getUserLikes,
excludeRetweet,
getSearch,
};