Minstrel
The FLOSS hybrid reading app
Built together by readers, for the readers
Developer Information
This page contains information useful for developers and book producers which might be interested in extending/working with Minstrel app.
If you are looking for help using Menestrello, the official built of the app from ReadBeyond, please consult the Menestrello Help page instead.
- App Overview
- Library
- Localization
- EPUB Reader
- CBZ Reader
- ABZ Reader
- Supporting new file formats
- Comments and bug reports
App Overview
- Hybrid app compiled using Apache Cordova 5.0.0
- Platforms: Android (4.0+) and iOS (6.0+)
- Minstrel Version: 3.0.1 (date 2015-05-20, build 7fa72ad0)
- Menestrello Version: 3.0.0 (date 2015-02-05, build 380f1dbb)
Library
iOS
Minstrel will read ABZ, CBZ, and EPUB files from the app Documents/
directory
and its subdirectories.
The user can copy files there:
- using iTunes, or
- downloading files from the Web using Safari, and selecting Open with Minstrel.
Android
Minstrel can open ABZ, CBZ, and EPUB files by:
- scanning one or more directories on the device storage (both internal memory or external sd cards) selected by the user,
- responding to a
VIEW intent
from the Download Manager/Notification Center or a file browser, or - responding to a
VIEW intent
from the browser (directly downloading the requested file).
If the user presses the Refresh button, the app will refresh the library by scanning the directories selected by the user as containing the publications.
You can change these directories by pressing the button Change library directory in Settings > Library.
To improve the speed of the scanning process, you might want to copy your eBooks into a single directory (possibly, with subdirectories), and select that directory only.
Cover thumbnail images are stored in the /INTERNALSD/minstrel/.thumbnails/
directory,
which can be safely deleted if you uninstalled the app and need space on your device.
The book assets are extracted into a /INTERNALSD/minstrel/tmp/
directory.
This directory is emptied as soon as a book is closed
and the user returns to the Library View.
You can safely delete the tmp
directory if need space on your device.
Important note: by default, Minstrel uses the /INTERNALSD/minstrel/
directory
as the main app directory, instead of using the standard /data/Android/app/
path,
since the latter directory might be inacessible to the user on some devices,
and we think that the user should be able to control the app behavior,
including the temporary data it writes.
Localization
Localization of the UI strings is managed by a custom JS library, able to load both JS-like files and PO files.
At the moment, the 8 available languages (DA, DE, EN, ES, FR, IT, PL, TR) are loaded from JS files located in the app package, but a future version of the app will load PO files from the user storage, allowing loading a new language by simply providing a user-created PO file.
Note: for DA, DE, ES, FR, PL, TR languages, many strings added in v3.0.0 have been translated automatically.
If you would like to clean them up, or you want to translate Minstrel in a new language,
please contact us (minstrel@readbeyond.it
).
We will be very happy to include your translation and credit you for your work.
EPUB reader
Rendering strategy
When the user opens an EPUB in the Library, the EPUB is unzipped into a temporary directory. A JS library parses the OPF and related files, and builds the data structures needed to render it (reading order, ToC, playlist, etc.).
Audio files associated with Media Overlays are unzipped "on demand", to reduce both the startup time and the disk consumption for the temporary directory. To reduce the transition time from a chapter/track to the next one, a preloading mechanism is in place. Note that every audio file required by the SMIL file referenced by an XHTML file is unzipped before the XHTML is rendered.
Once all required assets have been extracted to the temporary directory,
the app will load the source of the XHTML page into a special <div>
.
Currently, <iframe>
is not used due to several issues related to Cordova,
but future versions of the app might use it.
Note that the CSS files and <style>
elements of the EPUB will be applied together with
the CSS rules derived from the user preferences expressed through the app controls.
(See also below.)
Media Overlays limitations
Currently, most of the EPUB 3 Media Overlays specification is supported, except:
- skippability/escapability functions, and
- embedded media synchronization.
Moreover, epub:type
attributes are ignored.
As of v3.0.0, SMIL files referencing more XHTML or audio files are supported,
as well as non-contiguous (clipBegin(i+1) != clipEnd(i)
) sequences.
Minstrel also supports the proposed <meta property="media:paused-class">pausedClass</meta>
meta,
which applies pausedClass
to the current MO element, if the playback is paused,
similarly to <meta property="media:active-class">
.
Pre-paginated (Fixed Layout) limitations
Support for pre-paginated EPUB 3 (and hybrid EPUB 3) is very experimental. Currently only single-page rendering is supported.
JavaScript limitations
Support for running embedded JavaScript is very experimental.
User must explicitly enable this function in "Settings > EPUB > Advanced".
When disabled, all <script>
elements are removed.
When enabled, all <script>
elements will be injected,
however only the <body onload="...">
function is run automatically on page load.
Other functions (e.g., attached to element events) are run when needed.
The navigator.epubReadingSystem
object is exposed, with name Minstrel
.
Beyond exposing the properties/functions mandated by the EPUB 3 specification,
the navigator.epubReadingSystem
object (rs
for short below) offered by Minstrel
also provides the following:
rs.events.onApplyHighlightStyleChange(newValue)
eventrs.events.onApplyTypographicSettingsChange(newValue)
eventrs.events.onAutoScrollChange(newValue)
eventrs.events.onBackgroundColorChange(newValue)
eventrs.events.onFontColorChange(newValue)
eventrs.events.onFontFamilyChange(newValue)
eventrs.events.onFontSizeChange(newValue)
eventrs.events.onHighlightStyleChange(newValue)
eventrs.events.onLineSpacingChange(newValue)
eventrs.events.onMarginSizeChange(newValue)
eventrs.events.onMarginSizeChange(newValue)
eventrs.events.onOrientationChange(orientation, isOrientationLocked)
eventrs.events.onPlaybackSpeedChange(newValue)
eventrs.events.onPlaybackVolumeChange(newValue)
eventrs.events.onTapToPlayChange(newValue)
eventrs.events.onTextAlignChange(newValue)
eventrs.events.onTextTransformChange(newValue)
eventrs.settings.injectUserCSS
property (values:true
,false
)rs.settings.stripPublisherCSS
property (values:true
,false
)rs.ui.brightness
property (value: float between 0.0 and 1.0)rs.ui.language
property (value: 2-letters ISO code for the UI language)rs.ui.orientation
property (values:portrait
,landscape
,reversed portrait
,reverse landscape
)rs.ui.orientationLock
property (values:true
,false
)rs.ui.theme
property (values:light
ordark
)
Please see this demo EPUB for an usage example.
Note: the above API is extremely experimental and it might change in the next version of the app.
Linear="no" options
In "Settings > EPUB > Advanced", the user can select whether spine items
with linear="no"
should be rendered in the linear progression of the EPUB assets,
and whether an element with linear="no"
should be considered as a cul-de-sac,
that is, whether transitioning out of it should be possible only via the ToC or a link.
Moreover, if the <metadata>
element of the EPUB OPF file contains a
<meta name="nonlinear:crossable" content="false"/>
element,
the EPUB viewer will treat all linear="no"
spine items as culs-de-sac.
CSS Overriding/Custom CSS
When the user enables the "Ignore publisher's CSS" option,
all <style>
elements and linked CSS will be removed.
When the user enables the "Use custom CSS" option,
the app will look for a custom.css
(or custom.night.css
if the night mode is active)
CSS file in the app root directory (e.g., /sdcard/minstrel/custom.css
in Android)
and it will apply it to rendered EPUB files.
Note that the above two settings are independent, and might conflict and/or complement each other. Moreover, they are both independent from the EPUB Reader preferences (font face, size, etc.).
ReadBeyond customizations
When this "Settings > EPUB > Advanced" option is enabled, it will perform the following customizations:
- resize the ebook cover image to fill the viewport (an heuristic is applied to "recognize" the cover spine item)
- show the Playlist popup instead of rendering
playlist.xhtml
- remove the header
<div>
containing the<audio>
element and navigation links in ReadBeyond EPUB 3 Audio-eBooks
EPUB files from third party should be unaffected by this option. However, you can always switch it off in "Settings > EPUB > Advanced".
CBZ reader
Minstrel can display CBZ files, that is, ZIP of image files.
The rendering order is given by the lexicographic order of the ZIP entries. For example:
001 foo.jpg
002 bar.jpg
003 baz.png
...
010 foo.jpg
011 bar baz.jpg
...
Minstrel supports nested subdirectories, taking the full path into account:
foo/bar/01/01 foo.jpg
foo/bar/01/02 bar.jpg
foo/bar/01/03 baz.png
foo/bar/02/01.png
foo/bar/02/02.jpg
foo/bar/02/03.jpg
foo/bar/02/04.gif
...
If a plain text metadata.txt
file exists inside the CBZ file,
Minstrel will try to read the publication metadata from it.
Example:
title: Bar Baz
author: Foo Foo
language: en
cover: path/to/my/cover.jpg
playlist: path/to/playlist.txt
series: Series name
seriesindex: 1
All fields are optional.
The cover
field specifies the path (relative to metadata.txt
)
of the cover image.
If none is specified, the app will look for cover.jpg
or cover.png
.
If none is found, the first image of the CBZ will be used as cover image.
The playlist
field specifies the path (relative to metadata.txt
)
of the playlist file, which might override the default lexicographic order:
album1/01.png
5
Caption of image 01.png
album1/13.png
5
Caption of second image
album2/04.png
10
Caption of third image
For each image, the first row specifies the image path (relative to the playlist.txt
file),
the second row an image duration (in seconds), and the third an image caption.
The image duration and caption are used in presentation mode, and they are optional.
Each image block is terminated by a blank line.
ABZ reader
Minstrel can play ABZ files, that is, ZIP of audio files.
The playing order is given by the lexicographic order of the ZIP entries. For example:
001 title.mp3
002 another title.mp3
003 foo.mp3
...
010 bar.mp3
011 baz.mp3
...
Minstrel supports nested subdirectories, taking the full path into account:
foo/bar/01/01.mp3
foo/bar/01/02.wav
foo/bar/01/03.mp4
foo/bar/02/01.aac
foo/bar/02/02.mp3
foo/bar/02/03.mp3
foo/bar/02/04.mp3
...
If a plain text metadata.txt
file exists inside the ABZ file,
Minstrel will try to read the publication metadata from it.
Example:
title: Bar Baz
author: Foo Foo
narrator: Nar Rator
language: en
cover: path/to/my/cover.jpg
playlist: path/to/playlist.m3u
duration: 01:23:45
series: Series name
seriesindex: 3
All fields are optional.
The cover
field specifies the path (relative to metadata.txt
)
of the cover image.
If none is specified, the app will look for a file named cover.jpg
or cover.png
.
The playlist
field specifies the path (relative to metadata.txt
)
of an M3U playlist.
If none is specified, the app will look for a file named playlist.m3u
.
If none is found, the app will play the audio files according to the
lexicographic order of the ZIP entry names.
Currently, the app does not extract metadata/cover image from the audio files (e.g., ID3 tags from MP3 files). A future version of the app might do so.
Supporting new file formats
As of v3.0.0, Minstrel code has been rewritten to make adding a new file format extremely simple.
In practical terms, this means developing:
- a native (= Java, ObjC) "discovery" function that inspects a given file on disk, and returns whether it is supported and, if so, extracts its metadata for the Library View
- a "reader" HTML+JS page; the app common JS libs offer support for functions like zipping/unzipping/loading settings, etc.
- optionally, a user-controllable "settings" HTML+JS page
For instance, in our experimental branches (i.e., not available in the public app yet) we have a PDF reader (powered by PDF.js) and a Markdown reader/writer (powered by marked.js).
Comments and bug reports
- GitHub: https://github.com/readbeyond/minstrel
- Email:
minstrel@readbeyond.it
- Web: http://www.readbeyond.it/minstrel/