aboutsummaryrefslogtreecommitdiff
path: root/README.md
blob: f643795018af71e05b919ba09957a6ad4655efef (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
![][image]

## About

`nov.el` provides a major mode for reading EPUB documents.

Features:

- Basic navigation (jump to TOC, previous/next chapter)
- Remembering and restoring the last read position
- Jump to next chapter when scrolling beyond end
- Storing and following Org links to EPUB files
- Renders EPUB2 (.ncx) and EPUB3 (<nav>) TOCs
- Hyperlinks to internal and external targets
- Supports textual and image documents
- Info-style history navigation
- View source of document files
- Metadata display
- Image rescaling

## Screenshot

![][screenshot]

## Installation

Set up the [MELPA] or [MELPA Stable] repository if you haven't already
and install with `M-x package-install RET nov RET`.

## Setup

By default, `nov.el` uses `unzip` on `PATH` to extract EPUB files. You
can customize `nov-unzip-program` if it is located elsewhere. You can
also customize `nov-unzip-args` if you use a different decompression
tool like `bsdtar`. It must accept a target `directory` where nov
unzips the EPUB `filename`.

    (setq nov-unzip-program (executable-find "bsdtar")
          nov-unzip-args '("-xC" directory "-f" filename))

You'll also need an Emacs compiled with `libxml2` support, otherwise
rendering will fail.

Put the following in your init file:

    (add-to-list 'auto-mode-alist '("\\.epub\\'" . nov-mode))

## Customization

While the defaults make for an acceptable reading experience, it can
be improved with any of the following changes:

### Default font

To change the default font, use `M-x customize-face RET
variable-pitch`, pick a different family, save and apply.  If you
dislike globally customizing that face, add the following to your init
file:

    (defun my-nov-font-setup ()
      (face-remap-add-relative 'variable-pitch :family "Liberation Serif"
                                               :height 1.0))
    (add-hook 'nov-mode-hook 'my-nov-font-setup)

To completely disable the variable pitch font, customize
`nov-variable-pitch` to `nil`.  Text will be displayed with the
default face instead which should be using a monospace font.

### Text width

By default text is filled by the window width.  You can customize
`nov-text-width` to a number of columns to change that:

    (setq nov-text-width 80)

It's also possible to set it to `t` to inhibit text filling, this can
be used in combination with `visual-line-mode` and packages such as
`visual-fill-column` to implement more flexible filling:

    (setq nov-text-width t)
    (setq visual-fill-column-center-text t)
    (add-hook 'nov-mode-hook 'visual-line-mode)
    (add-hook 'nov-mode-hook 'visual-fill-column-mode)

### Rendering

In case you're not happy with the rendering at all, you can either use
`nov-pre-html-render-hook` and `nov-post-html-render-hook` to adjust
the HTML before and after rendering or use your own rendering function
by customizing `nov-render-html-function` to one that replaces HTML in
a buffer with something nicer than the default output.

Here's an advanced example of text justification with the [justify-kp]
package:

    (require 'justify-kp)
    (setq nov-text-width t)

    (defun my-nov-window-configuration-change-hook ()
      (my-nov-post-html-render-hook)
      (remove-hook 'window-configuration-change-hook
                   'my-nov-window-configuration-change-hook
                   t))

    (defun my-nov-post-html-render-hook ()
      (if (get-buffer-window)
          (let ((max-width (pj-line-width))
                buffer-read-only)
            (save-excursion
              (goto-char (point-min))
              (while (not (eobp))
                (when (not (looking-at "^[[:space:]]*$"))
                  (goto-char (line-end-position))
                  (when (> (shr-pixel-column) max-width)
                    (goto-char (line-beginning-position))
                    (pj-justify)))
                (forward-line 1))))
        (add-hook 'window-configuration-change-hook
                  'my-nov-window-configuration-change-hook
                  nil t)))

    (add-hook 'nov-post-html-render-hook 'my-nov-post-html-render-hook)

This customization yields the following look:

![][screenshot-kp]

## Usage

Open the EPUB file with `C-x C-f ~/novels/novel.epub`, scroll with
`SPC` and switch chapters with `n` and `p`.  More keybinds can be
looked up with `F1 m`.

## Bugs

Invalid EPUB documents are *not* supported.  Please use [epubcheck] to
validate yours when running into an error.

In case the bug is specific to an EPUB document, please send attach it
to your email.  I'll try my best to figure out the error, but chances
are you can figure it out as well by using the source view (bound to
``v`` for the current document and ``V`` for the content file) to spot
the problematic XML.

## Alternatives

The first one I've heard of is [epubmode.el] which is, well, see for
yourself.  You might find [ereader] more useful, especially if you're
after Org integration and annotation support.

[image]: img/novels.gif
[screenshot]: img/scrot.png
[MELPA]: https://melpa.org/
[MELPA Stable]: https://stable.melpa.org/
[justify-kp]: https://github.com/Fuco1/justify-kp
[screenshot-kp]: img/justify-kp.png
[epubcheck]: https://github.com/IDPF/epubcheck
[epubmode.el]: https://www.emacswiki.org/emacs/epubmode.el
[ereader]: https://github.com/bddean/emacs-ereader