import { ensureDir } from "@std/fs"; import { serveDir, serveFile } from "@std/http/file-server"; import * as z from "@zod/mini"; import { db } from "./db.ts"; import { CompositeDidDocumentResolver, PlcDidDocumentResolver, WebDidDocumentResolver, } from "@atcute/identity-resolver"; import { VIDEO_PATTERN } from "../common/routes.ts"; const didResolver = new CompositeDidDocumentResolver({ methods: { plc: new PlcDidDocumentResolver(), web: new WebDidDocumentResolver(), }, }); async function fetchVideo(req: Request): Promise { if (req.method === "OPTIONS") { return new Response(null, { headers: { "access-control-allow-origin": "*", }, }); } if (req.method !== "POST") { return new Response("Method Not Allowed", { status: 405 }); } const BodySchema = z.object({ repo: z.string().check(z.startsWith("did:")), blob: z.string(), }); const body = BodySchema.parse(await req.json()); const existingVideo = db.getVideo(body.repo, body.blob); if (existingVideo !== undefined) { return new Response(JSON.stringify({ filename: existingVideo }), { headers: { "content-type": "application/json", "access-control-allow-origin": "*", }, }); } if (!db.inAllowlist(body.repo)) { return new Response( JSON.stringify({ error: "Denied", message: "repo is not allowlisted on AppView", }), { status: 400, headers: { "content-type": "application/json", "access-control-allow-origin": "*", }, } ); } const doc = await didResolver.resolve( body.repo as `did:${"plc" | "web"}:${string}` ); const pdsBaseURL = doc.service?.find( (it) => it.id === "#atproto_pds" )?.serviceEndpoint; if (!pdsBaseURL || typeof pdsBaseURL !== "string") return new Response(null, { status: 400 }); let filename: string = crypto.randomUUID(); { const getBlobURL = new URL("/xrpc/com.atproto.sync.getBlob", pdsBaseURL); getBlobURL.searchParams.set("did", body.repo); getBlobURL.searchParams.set("cid", body.blob); const blobResponse = await fetch(getBlobURL, { headers: { "user-agent": "video.cerulea.app" }, }); const contentType = blobResponse.headers.get("content-type"); if (contentType === "video/mp4") filename += ".mp4"; if (contentType === "video/webm") filename += ".webm"; await ensureDir("./data/videos"); using file = await Deno.open("./data/videos/" + filename, { write: true, createNew: true, }); await blobResponse.body?.pipeTo(file.writable); db.addVideo(body.repo, body.blob, filename); } return new Response(JSON.stringify({ filename }), { headers: { "content-type": "application/json", "access-control-allow-origin": "*", }, }); } export default { async fetch(req: Request, _info): Promise { const pathname = new URL(req.url).pathname; if (pathname === "/xrpc/blue.cerulea.video.fetchVideo") { return await fetchVideo(req); } if (pathname.startsWith("/user-content/")) { return await serveDir(req, { fsRoot: "./data/videos", quiet: true, enableCors: true, urlRoot: "user-content", }); } const videoRoute = VIDEO_PATTERN.exec(req.url); if (videoRoute) { return await serveFile(req, "./web/viewer.html"); } return await serveDir(req, { fsRoot: "./web", quiet: true }); }, } satisfies Deno.ServeDefaultExport;