summaryrefslogtreecommitdiff
path: root/src/reddit.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/reddit.ts')
-rw-r--r--src/reddit.ts146
1 files changed, 146 insertions, 0 deletions
diff --git a/src/reddit.ts b/src/reddit.ts
new file mode 100644
index 0000000..79475b1
--- /dev/null
+++ b/src/reddit.ts
@@ -0,0 +1,146 @@
+import type { TimePeriod } from './commands.js';
+
+export interface RedditPost {
+ id: string;
+ title: string;
+ author: string;
+ score: number;
+ num_comments: number;
+ created_utc: number;
+ permalink: string;
+ url: string;
+ selftext: string;
+ is_gallery?: boolean;
+ over_18: boolean;
+ link_flair_text?: string;
+ media?: {
+ reddit_video?: {
+ fallback_url: string;
+ };
+ };
+ secure_media?: {
+ reddit_video?: {
+ fallback_url: string;
+ };
+ };
+}
+
+export interface RedditResponse {
+ data: {
+ children: Array<{
+ data: RedditPost;
+ }>;
+ };
+}
+
+type SortType = 'hot' | 'top';
+
+async function fetchRedditPosts(
+ sort: SortType = 'hot',
+ time: TimePeriod = 'day',
+): Promise<RedditPost[]> {
+ const url = `https://www.reddit.com/r/okbuddyumamusume/${sort}.json${sort === 'top' ? `?t=${time}` : ''}`;
+ const response = await fetch(url, {
+ headers: {
+ 'User-Agent': 'UmaBot/0.1.0',
+ },
+ });
+
+ if (!response.ok) {
+ let errorText = `Error fetching ${response.url}: ${response.status} ${response.statusText}`;
+
+ try {
+ const error = await response.text();
+
+ if (error) errorText = `${errorText} \n\n ${error}`;
+ } catch {
+ //
+ }
+
+ throw new Error(errorText);
+ }
+
+ const data: RedditResponse = await response.json();
+
+ return data.data.children.map((post) => post.data);
+}
+
+function filterPostsByFlair(
+ posts: RedditPost[],
+ excludedFlairs: string[] = [],
+ includedFlairs: string[] = [],
+): RedditPost[] {
+ return posts.filter((post) => {
+ if (post.is_gallery) return false;
+
+ const hasMedia =
+ post.media?.reddit_video?.fallback_url ||
+ post.secure_media?.reddit_video?.fallback_url ||
+ post.url;
+
+ if (!hasMedia) return false;
+
+ const postFlair = post.link_flair_text?.toLowerCase() || '';
+ const isNSFW = post.over_18 || postFlair.includes('nsfw');
+
+ if (
+ includedFlairs.length > 0 &&
+ includedFlairs.some((flair) => flair.toLowerCase() === 'nsfw')
+ )
+ if (includedFlairs.some((flair) => flair.toLowerCase() === 'nsfw'))
+ return isNSFW;
+
+ if (isNSFW) return false;
+
+ if (includedFlairs.length > 0)
+ return includedFlairs.some((flair) =>
+ postFlair.includes(flair.toLowerCase()),
+ );
+
+ if (excludedFlairs.length > 0)
+ return !excludedFlairs.some((flair) =>
+ postFlair.includes(flair.toLowerCase()),
+ );
+
+ return true;
+ });
+}
+
+function getRandomPost(posts: RedditPost[]): RedditPost {
+ if (posts.length === 0)
+ throw new Error('No posts found matching the criteria');
+
+ const randomIndex = Math.floor(Math.random() * posts.length);
+
+ return posts[randomIndex];
+}
+
+export async function getCutePost(): Promise<RedditPost> {
+ const posts = await fetchRedditPosts('hot');
+ const filteredPosts = filterPostsByFlair(posts, ['roleplay', 'announcement']);
+
+ return getRandomPost(filteredPosts);
+}
+
+export async function getRoleplayPost(): Promise<RedditPost> {
+ const posts = await fetchRedditPosts('hot');
+ const filteredPosts = filterPostsByFlair(posts, [], ['roleplay']);
+
+ return getRandomPost(filteredPosts);
+}
+
+export async function getNSFWPost(): Promise<RedditPost> {
+ const posts = await fetchRedditPosts('hot');
+ const filteredPosts = filterPostsByFlair(posts, [], ['nsfw']);
+
+ return getRandomPost(filteredPosts);
+}
+
+export async function getTopPost(
+ time: TimePeriod = 'day',
+): Promise<RedditPost> {
+ const posts = await fetchRedditPosts('top', time);
+ const filteredPosts = filterPostsByFlair(posts, ['roleplay', 'announcement']);
+
+ return getRandomPost(filteredPosts);
+}