/** * The Bandcamp route. * * @module */ import { Router } from "@oak/oak"; import type { APIResponse } from "../../shared/api.ts"; import { resolveBandcamp } from "../remote/bandcamp-streams.ts"; import type { Tralbum } from "../../shared/player.ts"; /** * The Bandcamp route, for the native player: * * - `GET /api/bandcamp/tracks?url=&force=` — public. Resolves a Bandcamp page * to its streamable tracks, at play time; `force=1` bypasses the cache. */ const bandcampRouter: Router = new Router(); // Public: it only reads a public page and returns URLs the same page already // hands any visitor. Errors are thrown as APIException and rendered by // errorMiddleware; the client treats any failure as "fall back to the iframe // embed". bandcampRouter.get("/api/bandcamp/tracks", async (ctx) => { const url = ctx.request.url.searchParams.get("url") ?? ""; const force = ctx.request.url.searchParams.get("force") === "1"; const responseBody: APIResponse = { success: true, data: await resolveBandcamp(url, { force }), }; // Private: the signed URLs in the body are per-fetch, so they must not be // held in a shared cache. Well inside the 24h signature life either way. ctx.response.headers.set("Cache-Control", "private, max-age=3600"); ctx.response.body = responseBody; }); export default bandcampRouter;