-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathadvent-scheduler.ts
More file actions
133 lines (109 loc) · 3.69 KB
/
advent-scheduler.ts
File metadata and controls
133 lines (109 loc) · 3.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
import { ChannelType, type Client } from 'discord.js';
import * as cron from 'node-cron';
import { promises as fs } from 'node:fs';
import { config } from '../env.js';
const TRACKER_FILE = config.adventOfCodeTrackerPath;
type TrackerData = {
[year: string]: number[];
};
export async function loadTracker(): Promise<TrackerData> {
try {
const data = await fs.readFile(TRACKER_FILE, 'utf-8');
return JSON.parse(data);
} catch {
// If file doesn't exist or can't be read, return empty object
return {};
}
}
export async function saveTracker(data: TrackerData): Promise<void> {
await fs.writeFile(TRACKER_FILE, JSON.stringify(data, null, 2), 'utf-8');
}
async function isDayPosted(year: number, day: number): Promise<boolean> {
const tracker = await loadTracker();
const yearData = tracker[year.toString()];
return yearData ? yearData.includes(day) : false;
}
async function markDayAsPosted(year: number, day: number): Promise<void> {
const tracker = await loadTracker();
const yearKey = year.toString();
if (!tracker[yearKey]) {
tracker[yearKey] = [];
}
if (!tracker[yearKey].includes(day)) {
tracker[yearKey].push(day);
tracker[yearKey].sort((a, b) => a - b);
await saveTracker(tracker);
}
}
async function createAdventPost(
client: Client,
channelId: string,
year: number,
day: number
): Promise<boolean> {
try {
const channel = await client.channels.fetch(channelId);
if (!channel) {
console.error(`❌ Advent of Code channel not found: ${channelId}`);
return false;
}
if (channel.type !== ChannelType.GuildForum) {
console.error(`❌ Advent of Code channel is not a forum channel. Type: ${channel.type}`);
return false;
}
const forumChannel = channel;
const title = `Day ${day}, ${year}`;
const content = `https://adventofcode.com/${year}/day/${day}`;
await forumChannel.threads.create({
name: title,
message: {
content: content,
},
});
console.log(`✅ Created Advent of Code post: ${title}`);
return true;
} catch (error) {
console.error(`❌ Failed to create Advent of Code post for day ${day}:`, error);
return false;
}
}
async function checkAndCreateTodaysPost(client: Client, channelId: string): Promise<void> {
const now = new Date();
const month = now.getUTCMonth(); // 0-indexed, so December is 11
const day = now.getUTCDate();
const year = now.getUTCFullYear();
if (month !== 11) {
return;
}
if (day < 1 || day > 12) {
return;
}
const alreadyPosted = await isDayPosted(year, day);
if (alreadyPosted) {
console.log(`ℹ️ Advent of Code post for ${year} day ${day} already exists`);
return;
}
const success = await createAdventPost(client, channelId, year, day);
if (success) {
await markDayAsPosted(year, day);
}
}
/**
* Initialize the Advent of Code scheduler
* Runs every day at midnight UTC-5 and checks if we should create a post
*/
export function initializeAdventScheduler(client: Client, channelId: string): void {
console.log('🎄 Initializing Advent of Code scheduler...');
checkAndCreateTodaysPost(client, channelId).catch((error) => {
console.error('❌ Error checking for Advent of Code post on startup:', error);
});
// Schedule to run every day at midnight UTC-5
// https://github.com/node-cron/node-cron?tab=readme-ov-file#cron-syntax
cron.schedule('0 5 * * *', () => {
console.log('⏰ Running scheduled Advent of Code check...');
checkAndCreateTodaysPost(client, channelId).catch((error) => {
console.error('❌ Error in scheduled Advent of Code check:', error);
});
});
console.log('✅ Advent of Code scheduler initialized (runs daily at midnight UTC)');
}