diff options
| author | Mohamed Bassem <me@mbassem.com> | 2025-06-01 20:46:41 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-06-01 20:46:41 +0100 |
| commit | ea1d0023bfee55358ebb1a96f3d06e783a219c0d (patch) | |
| tree | 5bddd451728cb7dd377574a9ea1ea591bca069c4 /packages/api/utils/assets.ts | |
| parent | 3afe1e21df6dcc0483e74e0db02d9d82af32ecea (diff) | |
| download | karakeep-ea1d0023bfee55358ebb1a96f3d06e783a219c0d.tar.zst | |
feat: Add support for public lists (#1511)
* WIP: public lists
* Drop viewing modes
* Add the public endpoint for assets
* regen the openapi spec
* proper handling for different asset types
* Add num bookmarks and a no bookmark banner
* Correctly set page title
* Add a not-found page
* merge the RSS and public list endpoints
* Add e2e tests for the public endpoints
* Redesign the share list modal
* Make NEXTAUTH_SECRET not required
* propery render text bookmarks
* rebase migration
* fix public token tests
* Add more tests
Diffstat (limited to 'packages/api/utils/assets.ts')
| -rw-r--r-- | packages/api/utils/assets.ts | 57 |
1 files changed, 57 insertions, 0 deletions
diff --git a/packages/api/utils/assets.ts b/packages/api/utils/assets.ts new file mode 100644 index 00000000..d8a726a6 --- /dev/null +++ b/packages/api/utils/assets.ts @@ -0,0 +1,57 @@ +import { Context } from "hono"; +import { stream } from "hono/streaming"; + +import { + createAssetReadStream, + getAssetSize, + readAssetMetadata, +} from "@karakeep/shared/assetdb"; + +import { toWebReadableStream } from "./upload"; + +export async function serveAsset(c: Context, assetId: string, userId: string) { + const [metadata, size] = await Promise.all([ + readAssetMetadata({ + userId, + assetId, + }), + + getAssetSize({ + userId, + assetId, + }), + ]); + + const range = c.req.header("Range"); + if (range) { + const parts = range.replace(/bytes=/, "").split("-"); + const start = parseInt(parts[0], 10); + const end = parts[1] ? parseInt(parts[1], 10) : size - 1; + + const fStream = createAssetReadStream({ + userId, + assetId, + start, + end, + }); + c.status(206); // Partial Content + c.header("Content-Range", `bytes ${start}-${end}/${size}`); + c.header("Accept-Ranges", "bytes"); + c.header("Content-Length", (end - start + 1).toString()); + c.header("Content-type", metadata.contentType); + return stream(c, async (stream) => { + await stream.pipe(toWebReadableStream(fStream)); + }); + } else { + const fStream = createAssetReadStream({ + userId, + assetId, + }); + c.status(200); + c.header("Content-Length", size.toString()); + c.header("Content-type", metadata.contentType); + return stream(c, async (stream) => { + await stream.pipe(toWebReadableStream(fStream)); + }); + } +} |
