|
@@ -0,0 +1,78 @@
|
|
|
|
|
+const sinceInput = document.querySelector('#since') as HTMLInputElement;
|
|
|
|
|
+const newbies = document.querySelector('textarea#newbies') as HTMLTextAreaElement;
|
|
|
|
|
+
|
|
|
|
|
+{
|
|
|
|
|
+ const twoDaysAgo = new Date();
|
|
|
|
|
+ twoDaysAgo.setUTCDate(twoDaysAgo.getUTCDate() - 2);
|
|
|
|
|
+ twoDaysAgo.setUTCHours(0, 0, 0, 0);
|
|
|
|
|
+ sinceInput.value = twoDaysAgo.toISOString().slice(0, 10);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+sinceInput.addEventListener('change', () => void render());
|
|
|
|
|
+render();
|
|
|
|
|
+
|
|
|
|
|
+async function render(): Promise<void> {
|
|
|
|
|
+ const loader = document.querySelector('#loader') as HTMLElement;
|
|
|
|
|
+ loader.style.display = 'block';
|
|
|
|
|
+ try {
|
|
|
|
|
+ await _render();
|
|
|
|
|
+ } catch (e) {
|
|
|
|
|
+ console.error(e);
|
|
|
|
|
+ }
|
|
|
|
|
+ loader.style.display = 'none';
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+async function _render(): Promise<void> {
|
|
|
|
|
+ if (sinceInput.valueAsDate === null) {
|
|
|
|
|
+ console.warn(sinceInput.value, 'is not a valid date');
|
|
|
|
|
+ newbies.value = '';
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ newbies.style.display = 'none';
|
|
|
|
|
+
|
|
|
|
|
+ const planets = ['Katoa'];
|
|
|
|
|
+ const joined: Map<string, Join> = new Map();
|
|
|
|
|
+ for (const planet of planets) {
|
|
|
|
|
+ const messages: Message[] = await fetchJSON('https://api.fnar.net/chat/messages?' + new URLSearchParams({
|
|
|
|
|
+ 'channel_names': planet + ' Global Site Owners',
|
|
|
|
|
+ 'updated_since': sinceInput.valueAsDate?.toISOString(),
|
|
|
|
|
+ }).toString());
|
|
|
|
|
+ for (const message of messages)
|
|
|
|
|
+ if (message.Type == 'JOINED') {
|
|
|
|
|
+ const old_join = joined.get(message.SenderUserName)
|
|
|
|
|
+ if (old_join === undefined || old_join.timestamp > message.MessageTimestamp)
|
|
|
|
|
+ joined.set(message.SenderUserName, {timestamp: message.MessageTimestamp, planet});
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const sortedJoined = Array.from(joined.entries()).sort((a, b) => a[1].timestamp - b[1].timestamp);
|
|
|
|
|
+ const lines: string[] = [];
|
|
|
|
|
+ for (const [username, join] of sortedJoined) {
|
|
|
|
|
+ const dtStr = new Date(join.timestamp).toISOString().replace('T', ' ').replace('Z', '');
|
|
|
|
|
+ lines.push(`${username}\t${dtStr}\t${join.planet}`);
|
|
|
|
|
+ }
|
|
|
|
|
+ newbies.value = lines.join('\n');
|
|
|
|
|
+ newbies.style.display = 'block';
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+document.querySelector('#copy')!.addEventListener('click', () => {
|
|
|
|
|
+ navigator.clipboard.writeText(newbies.value);
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+async function fetchJSON(url: string, options: RequestInit = {}): Promise<any> {
|
|
|
|
|
+ const controller = new AbortController();
|
|
|
|
|
+ const timeoutId = setTimeout(() => controller.abort(), 5000);
|
|
|
|
|
+ const doc = await fetch(url, {...options, signal: controller.signal}).then((r) => r.json());
|
|
|
|
|
+ clearTimeout(timeoutId);
|
|
|
|
|
+ return doc;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+interface Message {
|
|
|
|
|
+ Type: string;
|
|
|
|
|
+ MessageTimestamp: number;
|
|
|
|
|
+ SenderUserName: string;
|
|
|
|
|
+}
|
|
|
|
|
+interface Join {
|
|
|
|
|
+ timestamp: number;
|
|
|
|
|
+ planet: string;
|
|
|
|
|
+}
|