GithubHelp home page GithubHelp logo

edrlab / thorium-reader Goto Github PK

View Code? Open in Web Editor NEW
1.5K 47.0 137.0 39.13 MB

A cross platform desktop reading app, based on the Readium Desktop toolkit

Home Page: https://www.edrlab.org/software/thorium-reader/

License: BSD 3-Clause "New" or "Revised" License

HTML 5.37% TypeScript 63.00% JavaScript 25.04% CSS 1.94% Python 0.01% EJS 0.02% SCSS 4.43% Dockerfile 0.09% Shell 0.10%
typescript electron reader epub-reader epub epub3 lcp react redux opds opds-feed

thorium-reader's Introduction

Thorium Reader

Thorium Reader is an easy to use EPUB reading application for Windows 10/10S, MacOS and Linux. After importing e-books from a directory or OPDS feed, you'll be able to read on any screen size, customize layout settings, navigate via the table of contents or page list, set bookmarks ... A great care is taken to ensure the accessibility of the application for visual impaired people using NVDA, JAWS or Narrator.

Free application. No ads. No private data flowing anywhere.

This project is in constant evolution, corrections and new features will be added soon and your support is welcome for that. The application is based on the open-source Readium Desktop toolkit.

It is currently localized in following 25 languages:

  • (en) English
  • (fr) Français (French)
  • (fi) Suomi (Finish)
  • (de) Deutsch (German)
  • (es) Español (Spanish)
  • (nl) Nederlands (Dutch)
  • (ja) 日本語 (Japanese)
  • (ka) ქართული (Georgian)
  • (lt) Lietuvių (Lithuanian)
  • (pt-BR) Português Brasileiro (Portuguese - Brazil)
  • (pt-PT) Português (Portuguese - Portugal)
  • (zh-CN) 中文 - 中國/国 (Chinese trad.)
  • (zh-TW) 中文 - **/灣 (Chinese simp.)
  • (it) Italiano (Italian)
  • (ru) Русский (Russian)
  • (ko) 한국어 (Korean)
  • (sv) Svenska (Swedish)
  • (ca) Catalan
  • (gl) Galician
  • (eu) Euskadi (Basque)
  • (el) ελληνικός (Greek)
  • (bg) български (Bulgarian)
  • (hr) Hrvatski (Croatian)
  • (da) Dansk (Danish)
  • (sl) Slovenščina (Slovene)

See: https://github.com/edrlab/thorium-reader/wiki/Localization-(l10n)-language-translations

library publication info reader

Prerequisites

  1. NodeJS 18 (check with node --version)
  2. NPM 9 (check with npm --version)

Technologies

  • typescript
  • electron
  • reactjs
  • redux
  • saga
  • i18next

Quick start

Install dependencies

  • npm install (or npm ci): initialize local node_modules packages from dependencies declared in package.json (this will also automatically call a long-running compilation stage in npm run postinstall)
  • in case of failure to NPM "install" because of "Divina player" SHA integrity mismatch, please try running the following command in your shell: node scripts/package-lock-patch.js && cat package-lock.json | grep -i divina-player-js

Start application in development environment

(with hot-reload dev server, web inspectors / debuggers)

  • npm run start:dev (or npm run start:dev:quick to bypass TypeScript checks / launch the app faster)

Start application in production environment

  • npm start (or npm run start)

Build installers

  • npm run package:win or npm run package:mac or npm run package:linux

Code Signing information: https://github.com/edrlab/thorium-reader/wiki/Code-Signing

Command line

thorium <cmd> [args]

Commands:
  thorium opds <title> <url>  import opds feed
  thorium import <path>       import epub or lpcl file
  thorium read <title>        searches already-imported publications with the
                              provided TITLE, and opens the reader with the
                              first match
  thorium [path]              import and read an epub or lcpl file     [default]
  thorium completion          generate bash completion script

Positionals:
  path  path of your publication, it can be an absolute, relative path  [string]

Options:
  --version  Show version number                                       [boolean]
  --help     Show help                                                 [boolean]

[DEV] Architecture

Thorium-reader is composed of 3 parts:

  • One node.js main process (electron back-end)
  • One library window (chromium renderer)
  • One to N reader window(s) (chromium renderer)

Each part runs a model-controller and a view for the renderer process.

  • the model is a state container with Redux. It's based on flux architecture
  • the controller is a middleware from Redux named Redux-saga. It handles all side effects and application behaviour.
  • the view for the rendering is React with class components

To link these 3 parts we use:

Diagram

MVC

architecture diagram

API Concept

To have a POST request from a renderer process to the main process, we use the notion of API. It's not an http API but an RPC encapsuled one, to redux/redux-saga logic with Action and Reducer.

Here is a diagram of the communication:

api

Src:

  • src/main/redux/sagas/api/api.ts
  • src/common/redux/actions/api/index.ts
  • src/renderer/common/redux/reducers/api.ts

At the moment there are 17 API endpoints from (src/main/redux/sagas/api):

library:

  • apiapp:
    • apiapp/search : search a library from apiapp protocol
  • browser:
    • httpbrowser/browse : browse and parse an opds URL
  • opds:
    • opds/getFeed : get an opdsFeed with its identifier
    • opds/findAllFeed: get all opdsFeed saved
    • opds/deleteFeed: delete an opdsFeed with its identifier
    • opds/addFeed: add an opdsFeed
    • opds/getUrlWithSearchLinks: get the search URL from an opdsFeed
  • publication: (src/common/api/interface/publicationApi.interface.ts)
    • publication/get: get a publicationView from id
    • publication/delete: delete a publicationView from id
    • publication/findAll: get all publicationView
    • publication/findByTag: get all publicationView from a specific tag string
    • publication/updateTags: update tags list from a publication
    • publication/importFromLink: import a publication from an URL
    • publication/importFromFs: import a publication from a fileSystem path
    • publication/search: search publication from a query text
    • publication/searchEqTitrle: search publication by title matching
    • publication/exportPublication: export publication to the fileSystem

ACTION-REDUCER

From the main-process to the renderer-process, or from the renderer-process to the main-process.

List of all Actions in place (src/common/redux/actions):

  • auth: opds authentication
    • cancel
    • done
    • wipeData
  • catalog
    • getCatalog: ask to rehydrate catalogView in the libraryState
    • setCatalogView: response from getCatalog
    • setTagView: rehydrate tagStringView in the libraryState
  • dialog: modal dialog view in library,reader
    • closeRequest
    • openRequest
    • updateRequest
  • download: download queue in library
    • abort
    • done
    • progress
  • history: history opds feed
    • pushFeed
    • refresh
  • i18n
    • setLocale
  • import
    • verify: import verification process
  • keyboard: keyboard shortcut
    • reloadShortcut
    • setShortcut
    • showShortcut
  • lcp
    • renewPublication
    • returnPublication
    • unlockPublicationWithPassphrase
    • userKeyCheckRequest
  • load: main proceess busy or not
    • busy
    • iddle
  • net (not used)
  • reader
    • attachMode
    • clipboardCopy
    • closeRequest
    • closeRequestFromPublication
    • configSetDefault
    • detachModeRequest
    • detachModeSuccess
    • fullScreenRequest
    • openRequest
    • openError
    • setReduxState: trigger app persistence
  • session: saved session
    • enable
  • toast: toast notification library,reader
    • close
    • open

thorium-reader's People

Contributors

arthur-lemeur avatar cary-rowen avatar clebeaupin avatar danielweck avatar elcste avatar gautierchomel avatar hadriengardeur avatar horus68 avatar iisisrael avatar llemeurfr avatar maitreya2019 avatar manuellagrand avatar martinpub avatar mattgarrish avatar milliet avatar naglis avatar nvdaes avatar panac avatar peaceroad avatar probonopd avatar scarsniik avatar tofi86 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

thorium-reader's Issues

React DropZone: dual CommonJS vs. ECMAScript module export => Node require() loader fails with WebPack renderer bundle and externalized react-dropzone package.

The react-dropzone package comes in two flavours: CommonJS (supported by the Node CommonJS loader, and indicated by package.json main: ./dist/index.js), and ECMAScript module (supported by the WebPack bundle loader, and indicated by package.json module: ./dist/es/index.js).
Due to @types/react-dropzone, VSCode (and more generally-speaking, the TypeScript compiler) is perfectly happy with either TSX syntaxes:

  1. import { default as Dropzone } from "react-dropzone"; and <Dropzone />
  2. import { Dropzone } from "react-dropzone"; and <Dropzone.default />

This works fine in the WebPack require/loader too, when the react-dropzone package is injected in the code bundle (naturally, WebPack prefers ES modules instead of CommonJS, as this is good for dynamic imports and tree shaking).

However the import breaks when the package remains external (inside node_modules), which is a desirable optimization in development mode to minimize the compile times and bundle size (in addition to using HMR Hot Module Reload for local code). The import breaks because default is not handled this way in CommonJS.

The solution that works for me is to ensure that Dropzone is imported as CommonJS in all cases.
TSX: import * as Dropzone from "react-dropzone/dist"; and <Dropzone />
typings.d.ts (or declarations.d.ts): declare module "react-dropzone/dist";

Feature request: Implement targeting of a specific "topic" on reader startup

(I know, you're probably not looking for feature requests, but this should be really "easy", and will be a huge help to opening up the world of EPUB to the technical communication profession. Hoping I'm not overstepping here.)

Provide the ability to include a command line parameter that opens a specified EPUB and optionally a specified content document on application startup. This could be as basic as ..

<readium-app> book.epub#itemref-idref
  • If the specified book is already open, switch to the specified idref rather than opening a new window.
  • Preserve the application window size and position between instances.

A better implementation would be to provide a programmatic API (via DLL, etc) to this functionality rather than needing to use the CLI, but the CLI implementation is probably much easier and is quite sufficient (for an initial implementation).

Background:

The technical communication (techcomm) industry has made use of Online Help applications to deliver context sensitive documentation for many years. First with WinHelp and then HTML Help (CHM files). But Microsoft stopped supporting HTML Help many years ago, and techcomm has been scrambling for a replacement. Many companies are fine with delivering documentation as "web help" in a browser, but many still need to have a locally installed deliverable and still (for now) use HTML Help (on Windows only).

I see EPUB as a possible replacement for this deliverable. It fundamentally provides (or can provide) all of the necessary features, and is platform independent. I've developed prototypes for "EPUB Help" for a number of years and presented these at conferences. It mostly works. The main piece missing for a basic implementation is the ability for the main software application to launch a specific EPUB on the desired topic. Now that rendition:flow=scrolled-doc is available, I no longer need to do javascript hacks to get nice vertically scrolling topics (much better for reference documentation).

If a viable ereader was available that provided this basic functionality, I'd be able to encourage the tool vendors to update their publishing tools to provide better support for EPUB. Right now they say their clients aren't asking for it (which in my mind is because there are no readers that do what's needed to offer good techcomm deliverables)

There is reasonable interest in techcomm for use of EPUBs, but the ereaders and publishing tools are lacking in feature support. If Readium Desktop can provide more of these features, we may see more adoption.

readiumCssOnOff() function is called before webview is ready in navigator => nil pointer

Suggestion: rather than force readium-desktop design to figure-out when it is legal to invoke readiumCssOnOff() (i.e. once a publication is loaded, and its webviews have been created), it would be better to do a sanity check in the r2-navigator-js's code. The initial ReadiumCSS state is always pulled from the navigator anyway, as soon as it loads a publication (to avoid FOUC Flash Of Unstyled Content).

store for "reading location", navigator API setReadingLocationSaver()

(ReaderApp.tsx)

Same "pull" model as setReadiumCssJsonGetter(), but with setReadingLocationSaver() the parameters to save into DB storage are doc (spine item path/href relative to publication / zip archive root), and loc (CSS selector).
This is a "pull" design in the sense that the navigator will invoke this app-level store fonction at arbitrary times during the reading experience, for example every time a page is turned, or when the user clicks a spot in the document (to narrow down / guess the current reading location).

The saved reading location can then be restored by passing the doc + loc parameters to installNavigatorDOM() when the user re-opens the EPUB.

when import EPUB (into library) with multilingual title: React crash (requires deleting database)

The Readium2 webpub manifest can contain metadata title with map object instead of single string value, for example:

{ "en": "Mahabharata" }

=> this kills the library view, and happens again after closing+reopening the application.

The Redux Store state that causes problems is store.catalog.publications[i].title (object type instead of string), or any React component that expect to consume string values but gets object instead.

[UI/UX] Reading position

To be innovative we should have some kind of an indicator to display the current reading position (how much you have "read", depending on how far you have scrolled down an article).

Read this interesting post on the subject.
I found referece to this in another interesting post about pagination and word processors.

This is a place for your ideas about the best way to indicate his reading position to the user.

UI missing for`doTryLcpPass()` throw+catch / promise.reject error code

In both usages of doTryLcpPass() where the try+catch block captures Promise.reject (async/await syntax), the error code should be passed in the payload for lcpActions.ActionType.PassphraseSubmitError and lcpActions.ActionType.UserKeyCheckError.

Code references:
https://github.com/edrlab/readium-desktop/blob/feature/next-v1/src/main/redux/sagas/lcp.ts#L62
and
https://github.com/edrlab/readium-desktop/blob/feature/next-v1/src/main/redux/sagas/lcp.ts#L118

Then some UI should let the user know what the problem is. For example, 11 = "LICENSE_OUT_OF_DATE", as per the listing below:

            // DRMErrorCode (from r2-lcp-client)
            // 1 === NO CORRECT PASSPHRASE / UERKEY IN GIVEN ARRAY
            //     // No error
            //     NONE = 0,
            //     /**
            //         WARNING ERRORS > 10
            //     **/
            //     // License is out of date (check start and end date)
            //     LICENSE_OUT_OF_DATE = 11,
            //     /**
            //         CRITICAL ERRORS > 100
            //     **/
            //     // Certificate has been revoked in the CRL
            //     CERTIFICATE_REVOKED = 101,
            //     // Certificate has not been signed by CA
            //     CERTIFICATE_SIGNATURE_INVALID = 102,
            //     // License has been issued by an expired certificate
            //     LICENSE_SIGNATURE_DATE_INVALID = 111,
            //     // License signature does not match
            //     LICENSE_SIGNATURE_INVALID = 112,
            //     // The drm context is invalid
            //     CONTEXT_INVALID = 121,
            //     // Unable to decrypt encrypted content key from user key
            //     CONTENT_KEY_DECRYPT_ERROR = 131,
            //     // User key check invalid
            //     USER_KEY_CHECK_INVALID = 141,
            //     // Unable to decrypt encrypted content from content key
            //     CONTENT_DECRYPT_ERROR = 151

[UI/UX] Page numbers (`epub:type="pagebreak"`)

We’re collecting feedback for Readium CSS and some requests may exceed the project’s scope (designing a CSS baseline).

Managing page numbers is a critical issue, especially in education. Users may search for page numbers, check which page they are scanning/reading/referring to (so page number should be displayed), etc.

Something as simple as having the page number displayed inline would already be judged some kind of progress, extra points if displayed in the margin. I guess it shouldn’t reflow with font-size but I may be wrong.

The streamer is already taking care of the pagelist/navdoc so this is probably more of an UI/UX-focused issue that a dev issue. Correct me if I’m wrong.

Add a CNL logo in the "about" menu

The financial help of the CNL (Centre National du Livre) is instrumental in this work and we have to show it.

The initial text of the "About" screen will be:
"Copyright 2018 European Digital Reading Lab"
followed by the content of the BSD-3 license (https://opensource.org/licenses/BSD-3-Clause)
followed by some vertical spaces and an horizontal line then:
"Readium Desktop wouldn't have been developed without the financial help of the CNL (Centre National du Livre, France)."
followed by the logo of the CNL, found on http://www.centrenationaldulivre.fr/fr/usage_du_logo_du_cnl/.

Font size chooser / slider: stepped values rather than continuous

The ReadiumCSS documentation recommends the following enumeration:

https://github.com/readium/readium-css/blob/master/docs/CSS09-user_prefs.md#font-size-and-type-scale

75% | 87.5% | 100% | 112.5% | 137.5% | 150% | 162.5% | 175% | 200% | 225% | 250%

The r2-testapp-js Electron app utilizes a UI slider with stepped values at regular intervals, not exactly the same as the above enumeration, but close enough.

The current navigator implementation documents these values too (whilst allowing any arbitrary values, as this is not strictly enforced), but note that only --USER__fontSize is currently implemented, not --USER__typeScale (TODO?):

https://github.com/edrlab/r2-navigator-js/blob/develop/src/electron/renderer/webview/readium-css.ts#L452

Un/active button colors in main view

Currently active color is grey and unactive color is black
Switch this behaviour : grey color for unactive button and black color for active button

RangeError: Invalid time value for some EPUBs (date/time metadata)

RangeError: Invalid time value

Deprecation warning: value provided is not in a recognized RFC2822 or ISO format. moment construction falls back to js Date(), which is not reliable across all browsers and versions. Non RFC2822/ISO date formats are discouraged and will be removed in an upcoming major release. Please refer to http://momentjs.com/guides/#/warnings/js-date/ for more info.
Arguments:
[0] _isAMomentObject: true, _isUTC: false, _useUTC: false, _l: undefined, _i: --T00:00:00Z, _f: undefined, _strict: undefined, _locale: [object Object]
Error
    at Function.createFromInputFallback (r2-testapp-js/node_modules/moment/moment.js:324:94)
    at configFromString (r2-testapp-js/node_modules/moment/moment.js:2366:11)
    at configFromInput (r2-testapp-js/node_modules/moment/moment.js:2592:9)
    at prepareConfig (r2-testapp-js/node_modules/moment/moment.js:2575:9)
    at createFromConfig (r2-testapp-js/node_modules/moment/moment.js:2542:40)
    at createLocalOrUTC (r2-testapp-js/node_modules/moment/moment.js:2629:12)
    at createLocal (r2-testapp-js/node_modules/moment/moment.js:2633:12)
    at hooks (r2-testapp-js/node_modules/moment/moment.js:16:25)
    at fillPublicationDate (r2-testapp-js/node_modules/r2-shared-js/dist/es8-es2017/src/parser/epub.js:624:52)
    at Object.EpubParsePromise (r2-testapp-js/node_modules/r2-shared-js/dist/es8-es2017/src/parser/epub.js:332:5)
    at <anonymous>
    at process._tickCallback (internal/process/next_tick.js:188:7)

Keyboard interaction with React-MaterialUI: buttons onClick event called several times when pushed with space/enter key

This is a known bug in material-ui 0.20.0 (latest):
https://www.npmjs.com/package/material-ui

Issue:
mui/material-ui#9344

Pull Request (already merged in their master branch):
mui/material-ui#9439

v0.20.0 was published on December 4th:
https://github.com/mui-org/material-ui/commits/master

We will close this issue when a new release of material-ui is available.

PS: I personally check my NPM dependencies regularly using the ncu CLI:
https://www.npmjs.com/package/npm-check-updates
(alternatively, the David web app is great too, e.g.: https://david-dm.org/edrlab/r2-streamer-js )

levelUP / levelDOWN runtime error with `npm run start:dev`

npm install concludes with a full successful rebuild to target Electron (1.7.9/1.7.10), but the app starts with an error (see console message below). Any idea? Are you experiencing the same at your end?

[1] App threw an error during load
[1] AssertionError: .status required, old abstract-leveldown
[1]     at new LevelUP (/Users/danielweck/Code/readium-desktop/dist/main.js:69273:10)
[1]     at LevelUP (/Users/danielweck/Code/readium-desktop/dist/main.js:69250:12)
[1]     at PouchDB$2.LevelPouch (/Users/danielweck/Code/readium-desktop/dist/main.js:67882:144)
[1]     at PouchDB$2.JsonDownPouch (/Users/danielweck/Code/readium-desktop/dist/main.js:67611:83)
[1]     at new PouchDB$2 (/Users/danielweck/Code/readium-desktop/dist/main.js:17751:36)
[1]     at Object.<anonymous> (/Users/danielweck/Code/readium-desktop/dist/main.js:5592:23)
[1]     at __webpack_require__ (/Users/danielweck/Code/readium-desktop/dist/main.js:21:30)
[1]     at Object.<anonymous> (/Users/danielweck/Code/readium-desktop/dist/main.js:47451:14)
[1]     at __webpack_require__ (/Users/danielweck/Code/readium-desktop/dist/main.js:21:30)
[1]     at /Users/danielweck/Code/readium-desktop/dist/main.js:64:18

"loading" indicator (indefinitely spinning visuals) + blank overlay to hide EPUB content whilst loading / formating

In ReaderApp.tsx, the installNavigatorDOM() function attaches the navigator to an app-defined HTML "anchor" node (passed as a DOM element unique ID parameter).

The navigator emits a show/hide custom DOM event on this "anchor" element in order to let the app UI know that the EPUB content should be hidden/shown (for example during formatting operations, resizing, etc.).

The application can do whatever it likes with this event, or even ignore it (as is the case right now in readium-desktop). For example, the r2-testapp-js sample Electron app displays a white overlay with a spinning "loader" to let the user know that a long operation is taking place under the hood.

API:

import {
    DOM_EVENT_HIDE_VIEWPORT,
    DOM_EVENT_SHOW_VIEWPORT,
} from "@r2-navigator-js/electron/renderer/index";

anchorHtmlElement.addEventListener(DOM_EVENT_HIDE_VIEWPORT, () => {
    HIDE_WITH_LOADER();
});
anchorHtmlElement.addEventListener(DOM_EVENT_SHOW_VIEWPORT, () =>
    SHOW();
});

VSCode Electron "launch" debugger config does not work with externals in renderer process bundle

There's a weird "bug" (feature?) in the Electron CLI, whereby electron . (assuming package.json and a correct main property pointing to dist/main.js) is different than electron dist/main.js. The former works great, the latter breaks when Electron renderer process is launched from a code bundle that contains Node CommonJS require() calls to externalized packages.
Unfortunately, the VSCode launch configuration results in the latter. Thankfully, we can fix that by using an "attach" configuration to an existing Electron process.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.