Back

Version 5

1/10/2025
import { discordWebhook } from "https://esm.town/v/stevekrouse/discordWebhook";
import { socialDataSearch, Tweet } from "https://esm.town/v/stevekrouse/socialDataSearch";

// Customize your keywords and exclusions
const keywords = ["your_keyword1", "your_keyword2", "your_brand"];
const excludes = "-is:retweet -from:irrelevant_user";
const query = keywords.map(k => `"${k}"`).join(" OR ") + " " + excludes;

// Helper function to filter relevant tweets
function relevant(tweet: Tweet) {
return (
keywords.some(k => tweet.full_text?.includes(k))
|| tweet.entities.urls?.some(u => keywords.some(k => u.expanded_url?.includes(k)))
);
}

// Toggle between production and testing
const isProd = true;

export async function twitterAlert({ lastRunAt }: Interval) {
// Define search timeframe; this example scrapes the past 48 hours
const since = isProd
? lastRunAt ? Math.floor(lastRunAt.getTime() / 1000) : 0
: Math.floor((Date.now() - 2 * 24 * 60 * 60 * 1000) / 1000);

// Fetch tweets
const response = await socialDataSearch(`${query} since_time:${since}`);
if ("message" in response) throw new Error(response.message);

// Filter relevant tweets
const relevantTweets = response.tweets?.filter(relevant);
if (!relevantTweets?.length) return;

// Format notification content
const content = relevantTweets
.map(({ user: { screen_name }, id_str }) => `https://fxtwitter.com/${screen_name}/status/${id_str}`)
Updated: January 10, 2025