Skip to content

Commit

Permalink
Allow Epub generation from multiple bookmarks hoarder-app#295
Browse files Browse the repository at this point in the history
Added a library to generate epub files
added a button to create epubs for single link bookmarks
  • Loading branch information
kamtschatka committed Jul 16, 2024
1 parent 888dad6 commit 5fa19b9
Show file tree
Hide file tree
Showing 4 changed files with 200 additions and 13 deletions.
65 changes: 65 additions & 0 deletions apps/web/app/api/epub/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { inArray } from "drizzle-orm";
import epub, { Chapter } from "epub-gen-memory";

import { db } from "@hoarder/db";
import { bookmarkLinks } from "@hoarder/db/schema";

export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const assetIds = searchParams.getAll("assetId");

if (!assetIds || assetIds.length === 0) {
return new Response("", {
status: 404,
});
}

const bookmarkInformation = await db
.select({
title: bookmarkLinks.title,
htmlContent: bookmarkLinks.htmlContent,
})
.from(bookmarkLinks)
.where(inArray(bookmarkLinks.id, assetIds));

if (!bookmarkInformation || bookmarkInformation.length === 0) {
return new Response("", {
status: 404,
});
}

const chapters = bookmarkInformation.map((information) => {
return {
content: information.htmlContent ?? "",
title: information.title ?? "",
};
});

const title = getTitle(chapters);

const generatedEpub = await epub(title, chapters);

return new Response(generatedEpub, {
status: 200,
headers: {
"Content-Type": "application/epub+zip",
"Content-Disposition": `attachment; filename=${createFilename()}`,
},
});
}

function createFilename(): string {
const date = new Date();
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, "0");
const day = String(date.getDate()).padStart(2, "0");

return `${year}-${month}-${day}-hoarder-bookmarks.epub`;
}

function getTitle(chapters: Chapter[]): string {
if (chapters.length === 1 && chapters[0].title) {
return chapters[0].title;
}
return "Hoarder EPub export";
}
36 changes: 23 additions & 13 deletions apps/web/components/dashboard/bookmarks/BookmarkOptions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
import { useToast } from "@/components/ui/use-toast";
import { useClientConfig } from "@/lib/clientConfig";
import {
Download,
Link,
List,
ListX,
Expand Down Expand Up @@ -153,19 +154,28 @@ export default function BookmarkOptions({ bookmark }: { bookmark: ZBookmark }) {
<span>{bookmark.archived ? "Un-archive" : "Archive"}</span>
</DropdownMenuItem>
{bookmark.content.type === BookmarkTypes.LINK && (
<DropdownMenuItem
onClick={() => {
navigator.clipboard.writeText(
(bookmark.content as ZBookmarkedLink).url,
);
toast({
description: "Link was added to your clipboard!",
});
}}
>
<Link className="mr-2 size-4" />
<span>Copy Link</span>
</DropdownMenuItem>
<>
<DropdownMenuItem
onClick={() => {
navigator.clipboard.writeText(
(bookmark.content as ZBookmarkedLink).url,
);
toast({
description: "Link was added to your clipboard!",
});
}}
>
<Link className="mr-2 size-4" />
<span>Copy Link</span>
</DropdownMenuItem>

<DropdownMenuItem>
<Download className="mr-2 size-4"></Download>
<a href={`/api/epub?assetId=${bookmark.id}`}>
Download as EPUB
</a>
</DropdownMenuItem>
</>
)}
<DropdownMenuItem onClick={() => setTagModalIsOpen(true)}>
<Tags className="mr-2 size-4" />
Expand Down
1 change: 1 addition & 0 deletions apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"clsx": "^2.1.0",
"dayjs": "^1.11.10",
"drizzle-orm": "^0.29.4",
"epub-gen-memory": "^1.0.10",
"fastest-levenshtein": "^1.0.16",
"lucide-react": "^0.330.0",
"next": "14.1.4",
Expand Down
Loading

0 comments on commit 5fa19b9

Please sign in to comment.