Yu, Jia-Wei

1 Building a Better EPUB and PDF Reader

I have always struggled to find a PDF or EPUB reader that I actually enjoy using.

My workflow is already deeply integrated with the browser. I use its history and bookmarks all the time, so I would like to read PDFs and ebooks directly in the browser.

1.1 pdf.ts

A browser extension based on embedPDF. It intercepts file://*.pdf and https://*.pdf URLs and redirects them to the extension’s viewer.

More details and source code: jay-waves/pdf.ts

1.2 epub.ts

A Chrome extension based on foliate-js. It intercepts file://*.epub and https://*.epub URLs and redirects them to the extension’s reader.

More details and source code: jay-waves/epub.ts

1.3 Comparing Other Readers

1.3.1 Chrome PDF Viewer

Google’s design is consistent, but I do not find it attractive… The toolbar at the top is much too tall.

1.3.2 Adobe Acrobat

It is powerful, but most of its PDF editing features seem unnecessary for everyday reading.

1.3.3 SumatraPDF for EPUB

It has a Windows 7 look. It is lightweight and certainly has a geeky feel.

1.3.4 Readest for EPUB

I think it looks quite good, but recent updates keep adding features that do not make sense to me. Also, the web version cannot intercept file:// URLs directly, so you have to import files manually before reading them.

1.4 Supporting Multiple Platforms

Web apps run in a controlled browser sandbox, where the browser governs and checks their behavior. When turning a web app into a local Windows or Linux app, the hardest part is extending its access to the local system. Web apps have limited access to the filesystem, process control, and system integration such as file associations and startup tasks.

Take the browser File System Access API as an example. To read a file, the app must open a file picker and ask the user to select it and grant permission. To write to a file, Chromium-based browsers show a dialog asking the user to select the original file and grant permission; subsequent writes overwrite that file. Safari/WebKit and Firefox still do not support writable handles to local files, so they can only download a copy to a fixed download directory.

In other words, access is restricted, and browser APIs and capabilities also differ. Maintaining the app across browsers is difficult.

There are three common approaches:

  1. Use a browser shell such as Electron or Tauri. The app bundles a browser environment (or WebView) and gains most system-level permissions.
  2. Move operations to a remote service. User data is uploaded to a server or copied into the browser sandbox’s local storage, rather than kept in the user’s own directory.
  3. Use a local agent. A privileged background process runs on the user’s computer; the web app sends it requests through a localhost API, and the agent performs the operations.

Here are the design choices I made for each platform:

1.4.1 Chrome Extension

When a user opens a *.pdf or *.epub file, the browser opens its file:// URI. The extension listens for this and redirects the file to its own viewer.

When the user edits a file and needs to save it, a dialog asks where to write it. Choosing the original file overwrites it in place.

1.4.2 Web App

When the user opens jay-waves.cn/epub.ts, a welcome screen appears. The user selects or drops a file to open it in the reader. Because this follows a direct user action, Chromium-based browsers allow the app to request both read and write access.

When the user edits a file and saves it, Safari or Firefox triggers a download, while Chrome writes the changes back to the original file.

1.4.3 Windows Desktop App

I wrote a small Go launcher for the desktop app. It can run as a background service, though it does not do so automatically. For example, pdf.ts.exe embeds all the web app’s resources and registers itself as a PDF file handler.

When a PDF is opened, the web app’s resources are temporarily extracted and opened in the browser. When the user later saves changes, the web app communicates over the local network with the listening pdf.ts.exe, which performs the file write on its behalf.