Cognoscimus

Next.jsTypeScriptSupabaseS3 Object StoragePostgreSQL

A private reading place for the web, built for my own library. It started as a fork of Readest, an open-source reader, and was cut down to what a single person with a few invited friends needs: sign in, read your books in the browser, and lend a book to someone else for a limited time.

You can import EPUB, PDF, MOBI, CBZ and other formats, keep your reading position, highlights and notes in sync across devices, and share individual books with another registered user for 1, 7 or 30 days. When the time is up, or when you revoke the access, the book disappears from the other person's library.

The reading engine, the library and the annotation model come from Readest. Native apps, payment, analytics and all third-party integrations were removed. What is left is a web app on a stack I already use elsewhere: Next.js, Supabase for authentication and the database, and S3-compatible object storage for the book files.

The library was joined by Later, a part for saving and reading articles and links later, under the same account. It fetches a web page, cuts out the readable text and stores it for reading, highlighting, ordering and searching. A few people I know can be followed to discover what they share, and RSS feeds bring new posts. The ideas come from Omnivore and Raindrop.io; I took no code from either.

The app is invitation-only, so the Open app link leads to a sign-in page. The source code is public on GitHub, as the AGPL license requires for a modified version that is served over a network.

Features

Reading

  • EPUB, PDF, MOBI/AZW3, FB2, TXT and comic archives (CBZ) in one reader
  • Paginated and scrolled layout, themes, fonts, dark mode
  • Highlights, notes and bookmarks, exportable as Markdown
  • Dictionary lookup and translation of selected text
  • Reading progress and statistics

Library

  • Import by drag and drop, with covers and metadata read from the files
  • Groups, tags, search, reading status (unread, reading, finished)
  • Books live on the device after the first download; the cloud copy can be fetched again at any time
  • Per-user storage quota, so one account cannot fill the bucket

Sharing for a limited time

  • Share a book with another registered user by email and choose how long: 1, 7 or 30 days
  • The recipient finds it under "Shared with me" and reads it in the browser
  • The owner can revoke access at any moment, from the book or from the account page
  • A shared book stays on the recipient's device only: it is never uploaded, synced, exported or shared on, and it is removed when the grant ends
  • Access is checked on the server for every download, and the download link itself is valid for five minutes

Later: articles and links

  • Save an address: the readable text is cut out, cleaned and shown in a calm reader, with full-text search, reading progress and an archive
  • Every item has a kind: article, link, video or document. Shop pages, GitHub pages and PDFs are filed as links instead of as a poor article
  • Highlights with notes inside an article, plus a note on every item, links included
  • Nested collections, labels, saved views and bulk actions (archive, move, label, delete)
  • A trash with 30 days to restore
  • Save on the go through the share menu (mobile) or a bookmarklet (desktop)
  • Import from Raindrop: folders become collections, tags become labels
  • Fetching other people's addresses checks every redirect and refuses internal addresses

Later: people and sharing

  • One username for the whole app, private by default and found only by its exact name
  • Following is a request that you accept, decline or block
  • Share articles, or whole collections, with followers. Followers see only what was shared, and the rules live in the database
  • Send an article to a person. It reaches their library only after they open and save it
  • "Explore": a stream of everything the people you follow share, with kind, source, excerpt and note

Later: RSS feeds

  • Follow feeds (also by a website's address) and import OPML
  • A timer fetches due feeds, and new entries wait in their own stream until you save or dismiss them
  • Failing feeds are checked less often and pause themselves

Accounts and security

  • Invitation-only: sign-ups are disabled, users are invited by the admin
  • Sign in with email and password, or with a magic link
  • Row-level security in the database, so every user sees only their own rows
  • Book files are never public: the browser gets short-lived signed links, checked against the grant

Comics

  • CBZ opens directly; CBR (RAR) archives are converted once with a small script, without re-compressing the pages

Related Blog Posts