An unexpected error now sends a general message, and the log keeps the
text. A job no longer shows the path of its uploaded file. A cover is
cached only by the browser of the user.
Plain HTML, CSS and JavaScript modules, with no build step. Hash routes
and relative URLs make it work under any path. The job list is polled:
every 2 seconds while a job runs, and less often otherwise.
Logins follow shelfmark: none, CWA accounts, or a reverse proxy header.
CWA accounts are checked against the OPDS feed, with a lockout after
repeated wrong passwords. An API key works in every mode, and changes
need an X-Requested-With header or the key. URL_BASE serves the app
under a path prefix.