From 0d60b8c8235c3c07f675aba7a56dd37b62519f9e Mon Sep 17 00:00:00 2001 From: Joe Mou Date: Thu, 27 Aug 2026 14:08:06 -0400 Subject: Display PDF blobs GitHub renders a PDF with a viewer of its own and so ships no content for one, leaving the blob view with nothing to show. Its raw bytes come as application/octet-stream, which browsers download rather than display, so serve them from a new embed route that retypes them and point an at that. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01BErPR92xppzGFXkPqXPYj2 --- cgithub/src/app.ts | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'cgithub/src/app.ts') diff --git a/cgithub/src/app.ts b/cgithub/src/app.ts index 9781a98..33b408e 100644 --- a/cgithub/src/app.ts +++ b/cgithub/src/app.ts @@ -10,6 +10,7 @@ import { getGitHubLatestCommit, getGitHubOwner, getGitHubPulls, + getGitHubRaw, getGitHubRefs, getGitHubRelease, getGitHubReleases, @@ -120,6 +121,31 @@ export function createApp(eta: Eta) { ); }); + // This is not a native GitHub route, but instead it lets us render blob + // content whose raw headers prevent hotlinking. + app.get("/:owner/:repo/embed/:type/:branch/:path{.*}", async (c) => { + const { owner, repo, type, branch, path } = c.req.param(); + + if (type !== "pdf") { + return c.notFound(); + } + + let response: Response; + try { + response = await getGitHubRaw(owner, repo, branch, path); + } catch (e) { + c.status(e instanceof GitHubHTTPError ? (e.status as StatusCode) : 500); + return c.body(null); + } + + let contentType = response.headers.get("Content-Type"); + if (contentType === null || contentType === "application/octet-stream") { + contentType = "application/pdf"; + } + + return new Response(response.body, { headers: { "Content-Type": contentType } }); + }); + app.get("/:owner/:repo/issues", async (c) => { const { owner, repo } = c.req.param(); const q = c.req.query("q"); -- cgit v1.3.1