feat: set up service to fetch comic data

This commit is contained in:
2025-07-15 17:59:29 -07:00
parent 12e3c5b510
commit 9b34db3fed
3 changed files with 93 additions and 0 deletions

3
.gitignore vendored
View File

@ -40,3 +40,6 @@ testem.log
# System files
.DS_Store
Thumbs.db
# We upload this to our CDN.
comics.json

15
removeBadge.js Normal file
View File

@ -0,0 +1,15 @@
/**
* @copyright nhcarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
/**
* Run this in the Discord console to remove the bot badges from the app.
* This is how we create the appearance that the webhook is a user.
*/
const appBadges = document.querySelectorAll("[class^='botTag']")
for (const badge of appBadges) {
badge.remove();
}

75
src/app/comic-service.ts Normal file
View File

@ -0,0 +1,75 @@
/**
* @copyright nhcarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
import { Injectable } from "@angular/core";
const oneDay = 1000 * 60 * 60 * 24;
@Injectable({
providedIn: "root",
})
export class ComicService {
// eslint-disable-next-line @typescript-eslint/class-literal-property-style -- I should turn this rule off.
private readonly comicsUrl: string = "https://cdn.yurigpt.com/comics.json";
private ttl = 0;
private comics: Array<{
number: number;
title: string;
date: string;
}> = [];
public constructor() {
void this.loadComics();
}
private static isObject(object: unknown): object is Record<string, unknown> {
return typeof object === "object" && object !== null;
}
private static validateComics(
comics: unknown,
): comics is Array<{ number: number; title: string; date: string }> {
if (!Array.isArray(comics)) {
return false;
}
return comics.every((comic) => {
if (!ComicService.isObject(comic)) {
return false;
}
return (
"number" in comic
&& "title" in comic
&& "date" in comic
&& typeof comic["number"] === "number"
&& typeof comic["title"] === "string"
&& typeof comic["date"] === "string"
);
});
}
public async loadComics(): Promise<void> {
if (this.ttl > Date.now()) {
return;
}
this.comics = [];
const response = await fetch(this.comicsUrl);
const data: unknown = await response.json();
if (ComicService.validateComics(data)) {
this.comics = data.sort((a, b) => {
return a.number - b.number;
});
this.ttl = Date.now() + oneDay;
} else {
console.error("Invalid comics data format:", data);
}
}
public getComics(): Array<{ number: number; title: string; date: string }> {
return this.comics;
}
}