10// TODO: what if we want multiple in a message? like "meeting at 3pm (in 2 hours)"? should we document that you can press up arrow or allow multiple?
11// probably should just include a component dropdown that has a "repeat with" and multiselect
12// TODO: ideally handle the user's locale as sent by Discord.
13// TODO: rewrite README, probably with video
14// TODO: bot should reply with instructions when dm'ed and possibly not be ephemeral in dms
27// redirect to install page
28app.get("/", (c) =>
29 c.redirect(`https://discord.com/oauth2/authorize?client_id=${CLIENT_ID}`)
30);
31app.post("/api/interactions", verify, handleInteraction);
1import { InteractionResponseType } from "npm:discord-interactions";
2import { dateToUnixSeconds, generateFormatOptions } from "../util/dateUtils.ts";
3import * as chrono from "npm:chrono-node";
1import { InteractionResponseFlags } from "npm:discord-interactions";
2import {
3 dateToUnixSeconds,
10
11/**
12 * Generate a Discord timestamp string
13 */
14export const getDiscordTimestamp = (date: Date, format: TimestampFormatId) => {
15 return `<t:${Math.floor(date.getTime() / 1000)}:${format}>`;
16};
33 tzOffsetMinutes: number
34) => {
35 const discordTimestamp = getDiscordTimestamp(date, format);
36 const formatOptions = generateFormatOptions(date, tzOffsetMinutes);
37
40 {
41 type: 10,
42 content: `## ${discordTimestamp}`,
43 },
44 // Action Row with String Select
70 )}_. Correct? Copy the text below:
71${TICKS}
72${discordTimestamp}
73${TICKS}`,
74 },
28 const timezoneOffset = timezoneOffsetFromMinutes(tzOffsetMinutes);
29 return {
30 // Discord timestamp formats
31 [TimestampFormatId.ShortTime]: formatInTimeZone(
32 date,
4 InteractionResponseType,
5 InteractionType,
6} from "npm:discord-interactions";
7import handleTimestampAutocomplete from "../handlers/handleTimestampAutocomplete.ts";
8import handleTimestampCommand from "../handlers/handleTimestampCommand.ts";
9import { dateFromUnixSeconds, TimestampFormatId } from "../util/dateUtils.ts";
10import { createCroneMessageData } from "../util/discordFormatting.ts";
11
12/**
13 * Route the Discord interaction to the appropriate handler
14 */
15export async function handleInteraction(c: Context) {
3 InteractionResponseFlags,
4 InteractionResponseType,
5} from "npm:discord-interactions";
6import { TimestampFormatId } from "../util/dateUtils.ts";
7import {
8 createCroneMessageData,
9 formatErrorAsDiff,
10} from "../util/discordFormatting.ts";
11
12/**
31 rssUrl: string;
32 sourceFilter: string; // e.g., "Asura", "LINE Webtoon", etc.
33 color: number; // Discord embed color
34}
35
52];
53
54const DISCORD_WEBHOOK_URL = Deno.env.get("DISCORD_WEBHOOK_URL");
55const STORAGE_KEY_PREFIX = "manga_updates_";
56
123}
124
125// Send Discord webhook notification
126async function sendDiscordNotification(item: RSSItem, seriesConfig: SeriesConfig): Promise<void> {
127 if (!DISCORD_WEBHOOK_URL) {
128 throw new Error("DISCORD_WEBHOOK_URL environment variable is not set");
129 }
130
162 };
163
164 const response = await fetch(DISCORD_WEBHOOK_URL, {
165 method: "POST",
166 headers: {
172 if (!response.ok) {
173 const errorText = await response.text();
174 throw new Error(`Discord webhook failed: ${response.status} ${response.statusText} - ${errorText}`);
175 }
176}
203 try {
204 console.log(`Processing: ${item.title} for ${seriesConfig.name}`);
205 await sendDiscordNotification(item, seriesConfig);
206
207 // Mark as processed
240
241 // Validate environment variables
242 if (!DISCORD_WEBHOOK_URL) {
243 throw new Error("DISCORD_WEBHOOK_URL environment variable is not set. Please configure it in Val Town.");
244 }
245
1import { discordWebhook } from "https://esm.town/v/stevekrouse/discordWebhook/main.ts";
2import { Hono } from "npm:hono";
3import Stripe from "npm:stripe";
88
89 let editLink = `([edit](${sourceURL(Error())}))`;
90 await discordWebhook({
91 url: Deno.env.get("DISCORD_WEBHOOK_URL")!,
92 content: `🤖💸 [@${username}](https://val.town/u/${username}) bought $${dollars} Townie credits ${editLink}`,
93 flags: ["SUPPRESS_EMBEDS"],
253. Add in that `_session` cookie in your personal Townie
26
27If you have any questions, please reach out on [Discord](https://discord.val.town) or at townie@val.town.
11[Templates](https://www.val.town/explore/use-cases),
12[Showcase](https://www.val.town/explore/community-showcase) and
13[Discord](https://discord.val.town/)!
14
15Stay as long as you'd like in this project, or head to your main