newbies.ts 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. const sinceInput = document.querySelector('#since') as HTMLInputElement;
  2. const newbies = document.querySelector('textarea#newbies') as HTMLTextAreaElement;
  3. {
  4. const twoDaysAgo = new Date();
  5. twoDaysAgo.setUTCDate(twoDaysAgo.getUTCDate() - 2);
  6. twoDaysAgo.setUTCHours(0, 0, 0, 0);
  7. sinceInput.value = twoDaysAgo.toISOString().slice(0, 10);
  8. }
  9. let planets: string[];
  10. export function setupNewbies(setPlanets: string[]): void {
  11. planets = setPlanets;
  12. render();
  13. }
  14. sinceInput.addEventListener('change', () => void render());
  15. async function render(): Promise<void> {
  16. const loader = document.querySelector('#loader') as HTMLElement;
  17. loader.style.display = 'block';
  18. try {
  19. await _render();
  20. } catch (e) {
  21. console.error(e);
  22. }
  23. loader.style.display = 'none';
  24. }
  25. async function _render(): Promise<void> {
  26. if (sinceInput.valueAsDate === null) {
  27. console.warn(sinceInput.value, 'is not a valid date');
  28. newbies.value = '';
  29. return;
  30. }
  31. newbies.style.display = 'none';
  32. const joined: Map<string, Join> = new Map();
  33. for (const planet of planets) {
  34. const messages: Message[] = await fetchJSON('https://api.fnar.net/chat/messages?' +
  35. new URLSearchParams({'channel_names': planet + ' Global Site Owners'}).toString());
  36. for (const message of messages)
  37. if (message.Type == 'JOINED') {
  38. const oldJoin = joined.get(message.SenderUserName)
  39. if (oldJoin === undefined || oldJoin.timestamp > message.MessageTimestamp)
  40. joined.set(message.SenderUserName, {timestamp: message.MessageTimestamp, planet});
  41. }
  42. }
  43. const threshold = sinceInput.valueAsDate!.getTime();
  44. const sortedJoined = Array.from(joined.entries().filter(([_, join]) => join.timestamp >= threshold))
  45. .sort((a, b) => a[1].timestamp - b[1].timestamp);
  46. const lines: string[] = [];
  47. for (const [username, join] of sortedJoined) {
  48. const dtStr = new Date(join.timestamp).toISOString().replace('T', ' ').replace('Z', '');
  49. lines.push(`${username}\t${dtStr}\t${join.planet}`);
  50. }
  51. newbies.value = lines.join('\n');
  52. newbies.style.display = 'block';
  53. }
  54. document.querySelector('#copy')!.addEventListener('click', () => {
  55. navigator.clipboard.writeText(newbies.value);
  56. });
  57. async function fetchJSON(url: string, options: RequestInit = {}): Promise<any> {
  58. const controller = new AbortController();
  59. const timeoutId = setTimeout(() => controller.abort(), 5000);
  60. const doc = await fetch(url, {...options, signal: controller.signal}).then((r) => r.json());
  61. clearTimeout(timeoutId);
  62. return doc;
  63. }
  64. interface Message {
  65. Type: string;
  66. MessageTimestamp: number;
  67. SenderUserName: string;
  68. }
  69. interface Join {
  70. timestamp: number;
  71. planet: string;
  72. }