//Setup export default async function ({login, imports, data, q}, {enabled = false, token = null} = {}) { //Plugin execution try { //Check if plugin is enabled and requirements are met if ((!enabled)||(!q.tweets)) return null //Parameters override let {"tweets.limit":limit = 2, "tweets.user":username = data.user.twitterUsername} = q //Limit limit = Math.max(1, Math.min(10, Number(limit))) //Load user profile console.debug(`metrics/compute/${login}/plugins > tweets > loading twitter profile (@${username})`) const {data:{data:profile = null}} = await imports.axios.get(`https://api.twitter.com/2/users/by/username/${username}?user.fields=profile_image_url,verified`, {headers:{Authorization:`Bearer ${token}`}}) //Load tweets console.debug(`metrics/compute/${login}/plugins > tweets > querying api`) const {data:{data:tweets = []}} = await imports.axios.get(`https://api.twitter.com/2/tweets/search/recent?query=from:${username}&tweet.fields=created_at&expansions=entities.mentions.username`, {headers:{Authorization:`Bearer ${token}`}}) //Load profile image if (profile?.profile_image_url) { console.debug(`metrics/compute/${login}/plugins > tweets > loading profile image`) profile.profile_image = await imports.imgb64(profile.profile_image_url) } //Limit tweets if (limit > 0) { console.debug(`metrics/compute/${login}/plugins > tweets > keeping only ${limit} tweets`) tweets.splice(limit) } //Format tweets await Promise.all(tweets.map(async tweet => { //Mentions tweet.mentions = tweet.entities?.mentions.map(({username}) => username) ?? [] //Format text console.debug(`metrics/compute/${login}/plugins > tweets > formatting tweet ${tweet.id}`) tweet.text = imports.htmlescape( //Escape tags imports.htmlescape(tweet.text, {"<":true, ">":true}) //Mentions .replace(new RegExp(`@(${tweet.mentions.join("|")})`, "gi"), ` @$1 `) //Hashtags (this regex comes from the twitter source code) .replace(/(?#$1 `) //Line breaks .replace(/\n/g, "
") //Links .replace(/https?:[/][/](t.co[/]\w+)/g, ` $1 `) , {"&":true}) })) //Result return {username, profile, list:tweets} } //Handle errors catch (error) { let message = "An error occured" if (error.isAxiosError) { const status = error.response?.status const description = error.response?.data?.errors?.[0]?.message ?? null message = `API returned ${status}${description ? ` (${description})` : ""}` error = error.response?.data ?? null } throw {error:{message, instance:error}} } }