diff options
| author | seth <[email protected]> | 2024-07-29 04:53:25 -0400 |
|---|---|---|
| committer | GitHub <[email protected]> | 2024-07-29 04:53:25 -0400 |
| commit | 984f4cfa24ee7e421bb1fbdf5907ae60375cf9ef (patch) | |
| tree | f23c500548bdc82dfe4eb65233327312435ec6b6 /src/teawie.ts | |
| parent | 9358cb6437bbe257717fe6cfd113aa9c34054c6c (diff) | |
use github contents api for image urls + summer cleaning (#253)
* nix: alejandra -> nixfmt-rfc-style
* nix: pre-commit-hooks -> treefmt-nix
* nix: use corepack
* ci: cleanup workflows
* ci: use better dependabot scopes
* gitignore: extend with github templates
* remove teawie-archive submodule
* pnpm: 8.8.0 -> 9.6.0
* nix: add nrr to shell
* nix: add node lsps to shell
* use github contents api for image urls
* ci: cleanup workflows
* nix: add ci shell
* `octokit` -> `fetch` & cache responses
* nix: use nixpkgs wrangler
* nix: update flake.lock
Flake lock file updates:
• Updated input 'nixpkgs':
'github:NixOS/nixpkgs/d9c0b9d611277e42e6db055636ba0409c59db6d2' (2024-07-05)
→ 'github:NixOS/nixpkgs/038fb464fcfa79b4f08131b07f2d8c9a6bcc4160' (2024-07-28)
* tsconfig: use strictest
* adopt openapi
* package.json: rename to teawie-api
* nix: add treefmt to ci shell
* ci: add release gate
Diffstat (limited to 'src/teawie.ts')
| -rw-r--r-- | src/teawie.ts | 98 |
1 files changed, 98 insertions, 0 deletions
diff --git a/src/teawie.ts b/src/teawie.ts new file mode 100644 index 0000000..65d6617 --- /dev/null +++ b/src/teawie.ts @@ -0,0 +1,98 @@ +import { USER_AGENT } from "./consts"; +import { Endpoints } from "@octokit/types"; + +type repositoryPathContentsResponse = + Endpoints["GET /repos/{owner}/{repo}/contents/{path}"]["response"]; + +const GITHUB_API = "https://api.github.com"; + +// Teawie repository owner and name +const REPO_OWNER = "SympathyTea"; +const REPO_NAME = "Teawie-Archive"; + +// Subdirectories of the above repository containing files we want +const SUBDIRS = [ + "teawie-media/Original Teawies", + "teawie-media/Teawie Variants", + "teawie-media/Teawie in Places", + "teawie-media/Unfinished Teawies", +]; + +// File extensions we consider to be images +const IMAGE_EXTENSIONS = ["gif", "jpg", "jpeg", "png", "svg", "webp"]; + +const contentsOf = ( + path: string, +): Promise<repositoryPathContentsResponse["data"]> => + fetch(`${GITHUB_API}/repos/${REPO_OWNER}/${REPO_NAME}/contents/${path}`, { + headers: { + accept: "application/vnd.github+json", + "user-agent": USER_AGENT, + }, + }) + .then((response) => { + if (!response.ok) { + throw new Error( + `HTTP Error ${response.status}: ${response.statusText}`, + ); + } + + return response.json(); + }) + .then((json) => { + return json as repositoryPathContentsResponse["data"]; + }); + +const imageUrlsIn = ( + files: repositoryPathContentsResponse["data"], +): string[] => { + // NOTE: This is done because the response may only contain data + // for a single file's path + const filesArray = Array.isArray(files) ? files : [files]; + + return ( + filesArray + // Find *files* that are (probably) images and have a download URL + .filter( + (file) => + !Array.isArray(file) && + file.download_url && + file.type == "file" && + IMAGE_EXTENSIONS.includes(file.name.split(".").at(-1) ?? ""), + ) + .map((file) => { + // Should this happen? No + // Could it? I don't know + // But let's be safe :steamhappy: + if (!file.download_url) { + throw new Error( + `Could not find download URL for file "${file.name}"`, + ); + } + + return file.download_url; + }) + ); +}; + +export const imageUrls = async (kv: KVNamespace): Promise<string[]> => { + const cached = await kv.get("urls"); + if (cached) { + console.trace("Found Teawie URLs in cache!"); + return JSON.parse(cached); + } + + console.warn("Couldn't find Teawie URLs in cache! Fetching fresh ones"); + const fresh = await Promise.all(SUBDIRS.map(contentsOf)).then((responses) => { + // See the note above + const flatResponses = responses.flatMap((response) => + Array.isArray(response) ? response : [response], + ); + + return imageUrlsIn(flatResponses); + }); + + await kv.put("urls", JSON.stringify(fresh), { expirationTtl: 60 * 60 }); + + return fresh; +}; |
