Last active
July 15, 2023 11:50
-
-
Save scarf005/b399147ad55ee917eeb08b75eef0ba89 to your computer and use it in GitHub Desktop.
fetches advent of code inputs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as dotenv from "https://deno.land/[email protected]/dotenv/mod.ts" | |
import { basename } from "https://deno.land/[email protected]/path/mod.ts" | |
import { Command } from "https://deno.land/x/[email protected]/command/mod.ts" | |
import { z } from "https://deno.land/x/[email protected]/mod.ts" | |
import { asynciter } from "https://deno.land/x/[email protected]/mod.ts" | |
import { difference } from "https://deno.land/x/[email protected]/mod.ts" | |
import { match, P } from "npm:ts-pattern@^5.0.3" | |
const cookieKey = "AOC_SESSION" | |
const cookieSchema = z.string().min(1, "Session cannot be empty!") | |
const getCookie = async () => { | |
const env = Deno.env.get(cookieKey) ?? (await dotenv.load())[cookieKey] | |
return cookieSchema.parse(env) | |
} | |
type AuthedFetch = (input: RequestInfo | URL) => Promise<Response> | |
type MkAuthedFetch = (session: string) => AuthedFetch | |
/** Generate fetch with session cookie */ | |
const authedFetch: MkAuthedFetch = (session) => (input) => | |
fetch(input, { headers: { cookie: `session=${session}` } }) | |
type GetInput = (fetch: AuthedFetch) => (year: number) => (day: number) => Promise<string> | |
/** Fetches AOC input */ | |
const getInput: GetInput = (fetch) => (year) => async (day) => | |
(await fetch(`https://adventofcode.com/${year}/day/${day}/input`)).text() | |
/** if it's before December 1, return previous year */ | |
const getDefaultYear = () => { | |
const now = new Date() | |
const isDecember = now.getMonth() === 11 | |
return now.getFullYear() - (isDecember ? 0 : 1) | |
} | |
/** How many days of inputs are there for a given year */ | |
const countInputs = (year: number) => { | |
const now = new Date() | |
const { currentYear, currentMonth, currentDay } = { | |
currentYear: now.getFullYear(), | |
currentMonth: now.getMonth(), | |
currentDay: now.getDate(), | |
} | |
const countOngoing = () => | |
match(currentMonth).with(11, () => Math.min(currentDay, 25)).otherwise(() => 0) | |
const length = match(year) | |
.with(P.number.lt(2015 /* when AOC started */), P.number.gt(currentYear), () => 0) | |
.with(currentYear, countOngoing) | |
.otherwise(() => 25) | |
return new Set(Array.from({ length }, (_, i) => i + 1)) | |
} | |
const cachedInputs = async (path: string) => { | |
const result = await asynciter(Deno.readDir(path)) | |
.filter((file) => file.isFile && file.name.endsWith(".txt")) | |
.map(({ name }) => parseInt(basename(name), 10)) | |
.collect() | |
return new Set(result) | |
} | |
const main = () => | |
new Command() | |
.name("fetch-aoc") | |
.description("Fetch Advent of Code inputs.") | |
.option("-y, --year <year:number>", "year to fetch", { default: getDefaultYear() }) | |
.option("-E, --cookie <cookie:string>", "session cookie, defaults to AOC_SESSION env variable") | |
.option("--cache <path:string>", "path to cache inputs", { default: "./inputs" }) | |
.action(async ({ year, cache, cookie = getCookie() }) => { | |
const cachePath = `${cache}/${year}` | |
const uncachedInputs = difference(countInputs(year), await cachedInputs(cachePath)) | |
const size = uncachedInputs.size | |
if (size === 0) { | |
return console.log(`All inputs for ${year} are cached`) | |
} | |
console.log(`Fetching ${size} inputs for ${year}...`) | |
const query = getInput(authedFetch(await cookie))(year) | |
await asynciter([...uncachedInputs]) | |
.concurrentUnorderedMap(async (day) => ({ day, input: await query(day) })) | |
.concurrentUnorderedMap(({ day, input }) => | |
Deno.writeTextFile(`${cachePath}/${day}.txt`, input) | |
) | |
.collect() | |
}) | |
if (import.meta.main) { | |
await main().parse(Deno.args) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment