Git Product home page Git Product logo

nov.el's Introduction

nov.el's People

Contributors

aplaice avatar clemera avatar dov avatar hasimir avatar jakub-w avatar lujun9972 avatar wasamasa avatar xiongtx 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

nov.el's Issues

TOC navigation: nov-visit-relative-file: Couldn’t locate document

Perhaps I'm missing something, but I can't navigate to a location from the TOC with Enter.

Debugger entered--Lisp error: (error "Couldn’t locate document")
signal(error ("Couldn’t locate document"))
error("Couldn't locate document")
nov-visit-relative-file("Text/cover.html" nil)
apply(nov-visit-relative-file ("Text/cover.html" nil))
nov-browse-url(13)
funcall-interactively(nov-browse-url 13)
call-interactively(nov-browse-url nil nil)
command-execute(nov-browse-url)

nov-display-metadata non-string isbn

When issuing nov-display-metadata on an epub file, the identifier property returns a symbol, in this case urn:isbn:9781449328009. I got it to work by putting (format "%s" value) before the insert to guarantee that the type is correct. The fix could go in nov-content-metadata if you intend nov-metadata to be an alist of (symbol . string).

nov-metadata for the particular epub looks like:
((identifier . urn:isbn:9781449328009)
(title . "Database Design and Relational Theory")
(language . "en")
(contributor)
(coverage)
(creator . "C.J. Date")
(date . "2012-04-19")
(description . "

What makes this book different from others on database design? Many resources on design practice do little to explain the underlying theory, and books on design theory are aimed primarily at theoreticians. In this book, renowned expert Chris Date bridges the gap by introducing design theory in ways practitioners can understand—drawing on lessons learned over four decades of experience to demonstrate why proper database design is so critical in the first place.

")
(format)
(publisher . "O'Reilly Media")
(relation)
(rights . "Copyright © 2012 Chris Date")
(source)
(subject . "COMPUTERS / Database Management / General")
(type))

Inhibition of autosave and save questions deletes buffer-file-name

Hello! A while back I added support of nov.el to org-noter and I think it has been working well.

Org-noter has a feature to create the annotation session from the document itself, by finding a notes file in a parent directory. In order to do that, it needs to know the full name of the file, and up until now it was using buffer-file-name for that.

However, the line (set-visited-file-name nil t) ; disable autosaves and save questions explicitly deletes it in order to avoid saving the file incorrectly, I think. Is there a way to do that that doesn't involve deleting that variable?

Another thing you could do is save value of the variable before deleting it and then assigning it to another variable, I think that would work :)

We are tracking this issue on weirdNox/org-noter#26.

Apostrophes show up as \222

Opened the book "Zen and the art of Motorcycle Maintenance" and all the apostrophes show up as \222.

Not really sure how to make this easily reproducible since I can't share the book here.
A lot of other ebooks either show up completely garbled or say "Invalid epub" even though they work fine in Calibre.

Invalid image type

I built Emacs 26.2 on Gentoo with the following configure settings: --without-x --without-imagemagick --without-jpeg --without-png --without-gif --without-tiff.

But I get the following error messages when opening an EPUB book with images with nov.el:

Invalid image type ‘jpeg’

Or:

Invalid image type ‘gif’

Or:

Invalid image type ‘png’

I can reproduce this problem with multiple, different e-books.

I'm using nov.el 20190611.922 from MELPA.

Not working on windows

I'm using GNU Emacs 25.2.1 (x86_64-w64-mingw32), instelled using mingw/msys. Unzip (also installed from mingw/msys) is in PATH and works. libxml2 is also installed via msys. I tried opening SICP.epub, but it failed with the message Invalid EPUB file. However, on my linux machine this epub works fine.

Error on open some epub files

When open some EPUB files, nov report error:

Debugger entered--Lisp error: (args-out-of-range [(ncx . "/tmp/nov-3Y4gmG.epub/OEBPS/toc.ncx") (id_1 . "/tmp/nov-3Y4gmG.epub/OEBPS/cover1.html") (id_2 . "/tmp/nov-3Y4gmG.epub/OEBPS/text00000.html")] 6)
  aref([(ncx . "/tmp/nov-3Y4gmG.epub/OEBPS/toc.ncx") (id_1 . "/tmp/nov-3Y4gmG.epub/OEBPS/cover1.html") (id_2 . "/tmp/nov-3Y4gmG.epub/OEBPS/text00000.html")] 6)
  (let* ((document (aref nov-documents nov-documents-index)) (id (car document)) (path (cdr document)) (imagep (--find (string-match-p (car it) path) image-type-file-name-regexps)) (default-directory (file-name-directory path)) buffer-read-only) (erase-buffer) (cond (imagep (nov-insert-image path)) ((and (version< nov-epub-version "3.0") (eq id nov-toc-id)) (insert (nov-ncx-to-html path))) (t (insert (nov-slurp path)))) (when (not imagep) (funcall nov-render-html-function)) (goto-char (point-min)))
  nov-render-document()
  (let ((index (cdr (assq 'index place))) (point (cdr (assq 'point place)))) (setq nov-documents-index index) (nov-render-document) (goto-char point))
  (if place (let ((index (cdr (assq 'index place))) (point (cdr (assq 'point place)))) (setq nov-documents-index index) (nov-render-document) (goto-char point)) (nov-render-document))
  (let ((place (nov-saved-place (cdr (assq 'identifier nov-metadata))))) (if place (let ((index (cdr (assq 'index place))) (point (cdr (assq 'point place)))) (setq nov-documents-index index) (nov-render-document) (goto-char point)) (nov-render-document)))
  (let ((delay-mode-hooks t)) (special-mode) (setq major-mode 'nov-mode) (setq mode-name "EPUB") (progn (if (get 'special-mode 'mode-class) (put 'nov-mode 'mode-class (get 'special-mode 'mode-class))) (unless (keymap-parent nov-mode-map) (set-keymap-parent nov-mode-map (current-local-map))) (let ((parent (char-table-parent nov-mode-syntax-table))) (unless (and parent (not (eq parent (standard-syntax-table)))) (set-char-table-parent nov-mode-syntax-table (syntax-table)))) (unless (or (abbrev-table-get nov-mode-abbrev-table :parents) (eq nov-mode-abbrev-table local-abbrev-table)) (abbrev-table-put nov-mode-abbrev-table :parents (list local-abbrev-table)))) (use-local-map nov-mode-map) (set-syntax-table nov-mode-syntax-table) (setq local-abbrev-table nov-mode-abbrev-table) (add-hook 'kill-buffer-hook 'nov-clean-up nil t) (add-hook 'kill-emacs-hook 'nov-clean-up-all) (add-hook 'change-major-mode-hook 'nov-clean-up nil t) (when (not buffer-file-name) (error "EPUB must be associated with file")) (setq nov-temp-dir (make-temp-file "nov-" t ".epub")) (let ((exit-code (nov-unzip-epub nov-temp-dir buffer-file-name))) (when (not (integerp exit-code)) (nov-clean-up) (error "EPUB extraction aborted by signal %s" exit-code)) (when (not (zerop exit-code)) (nov-clean-up) (error "EPUB extraction failed with exit code %d" exit-code))) (when (not (nov-epub-valid-p nov-temp-dir)) (nov-clean-up) (error "Invalid EPUB file")) (let* ((content (nov-slurp (nov-container-filename nov-temp-dir) t)) (content-file (->> (nov-container-content-filename content) (nov-make-path nov-temp-dir))) (work-dir (file-name-directory content-file)) (content (nov-slurp content-file t))) (setq nov-content-file content-file) (setq nov-epub-version (nov-content-version content)) (setq nov-metadata (nov-content-metadata content)) (setq nov-documents (->> (nov-content-files work-dir content) (apply 'vector))) (setq nov-documents-index 0)) (setq buffer-undo-list t) (set-visited-file-name nil t) (let ((place (nov-saved-place (cdr (assq 'identifier nov-metadata))))) (if place (let ((index (cdr (assq 'index place))) (point (cdr (assq 'point place)))) (setq nov-documents-index index) (nov-render-document) (goto-char point)) (nov-render-document))))
  (progn (make-local-variable 'delay-mode-hooks) (let ((delay-mode-hooks t)) (special-mode) (setq major-mode 'nov-mode) (setq mode-name "EPUB") (progn (if (get 'special-mode 'mode-class) (put 'nov-mode 'mode-class (get 'special-mode 'mode-class))) (unless (keymap-parent nov-mode-map) (set-keymap-parent nov-mode-map (current-local-map))) (let ((parent (char-table-parent nov-mode-syntax-table))) (unless (and parent (not (eq parent (standard-syntax-table)))) (set-char-table-parent nov-mode-syntax-table (syntax-table)))) (unless (or (abbrev-table-get nov-mode-abbrev-table :parents) (eq nov-mode-abbrev-table local-abbrev-table)) (abbrev-table-put nov-mode-abbrev-table :parents (list local-abbrev-table)))) (use-local-map nov-mode-map) (set-syntax-table nov-mode-syntax-table) (setq local-abbrev-table nov-mode-abbrev-table) (add-hook 'kill-buffer-hook 'nov-clean-up nil t) (add-hook 'kill-emacs-hook 'nov-clean-up-all) (add-hook 'change-major-mode-hook 'nov-clean-up nil t) (when (not buffer-file-name) (error "EPUB must be associated with file")) (setq nov-temp-dir (make-temp-file "nov-" t ".epub")) (let ((exit-code (nov-unzip-epub nov-temp-dir buffer-file-name))) (when (not (integerp exit-code)) (nov-clean-up) (error "EPUB extraction aborted by signal %s" exit-code)) (when (not (zerop exit-code)) (nov-clean-up) (error "EPUB extraction failed with exit code %d" exit-code))) (when (not (nov-epub-valid-p nov-temp-dir)) (nov-clean-up) (error "Invalid EPUB file")) (let* ((content (nov-slurp (nov-container-filename nov-temp-dir) t)) (content-file (->> (nov-container-content-filename content) (nov-make-path nov-temp-dir))) (work-dir (file-name-directory content-file)) (content (nov-slurp content-file t))) (setq nov-content-file content-file) (setq nov-epub-version (nov-content-version content)) (setq nov-metadata (nov-content-metadata content)) (setq nov-documents (->> (nov-content-files work-dir content) (apply 'vector))) (setq nov-documents-index 0)) (setq buffer-undo-list t) (set-visited-file-name nil t) (let ((place (nov-saved-place (cdr (assq 'identifier nov-metadata))))) (if place (let ((index (cdr (assq 'index place))) (point (cdr (assq 'point place)))) (setq nov-documents-index index) (nov-render-document) (goto-char point)) (nov-render-document)))))
  (delay-mode-hooks (special-mode) (setq major-mode 'nov-mode) (setq mode-name "EPUB") (progn (if (get 'special-mode 'mode-class) (put 'nov-mode 'mode-class (get 'special-mode 'mode-class))) (unless (keymap-parent nov-mode-map) (set-keymap-parent nov-mode-map (current-local-map))) (let ((parent (char-table-parent nov-mode-syntax-table))) (unless (and parent (not (eq parent (standard-syntax-table)))) (set-char-table-parent nov-mode-syntax-table (syntax-table)))) (unless (or (abbrev-table-get nov-mode-abbrev-table :parents) (eq nov-mode-abbrev-table local-abbrev-table)) (abbrev-table-put nov-mode-abbrev-table :parents (list local-abbrev-table)))) (use-local-map nov-mode-map) (set-syntax-table nov-mode-syntax-table) (setq local-abbrev-table nov-mode-abbrev-table) (add-hook 'kill-buffer-hook 'nov-clean-up nil t) (add-hook 'kill-emacs-hook 'nov-clean-up-all) (add-hook 'change-major-mode-hook 'nov-clean-up nil t) (when (not buffer-file-name) (error "EPUB must be associated with file")) (setq nov-temp-dir (make-temp-file "nov-" t ".epub")) (let ((exit-code (nov-unzip-epub nov-temp-dir buffer-file-name))) (when (not (integerp exit-code)) (nov-clean-up) (error "EPUB extraction aborted by signal %s" exit-code)) (when (not (zerop exit-code)) (nov-clean-up) (error "EPUB extraction failed with exit code %d" exit-code))) (when (not (nov-epub-valid-p nov-temp-dir)) (nov-clean-up) (error "Invalid EPUB file")) (let* ((content (nov-slurp (nov-container-filename nov-temp-dir) t)) (content-file (->> (nov-container-content-filename content) (nov-make-path nov-temp-dir))) (work-dir (file-name-directory content-file)) (content (nov-slurp content-file t))) (setq nov-content-file content-file) (setq nov-epub-version (nov-content-version content)) (setq nov-metadata (nov-content-metadata content)) (setq nov-documents (->> (nov-content-files work-dir content) (apply 'vector))) (setq nov-documents-index 0)) (setq buffer-undo-list t) (set-visited-file-name nil t) (let ((place (nov-saved-place (cdr (assq 'identifier nov-metadata))))) (if place (let ((index (cdr (assq 'index place))) (point (cdr (assq 'point place)))) (setq nov-documents-index index) (nov-render-document) (goto-char point)) (nov-render-document))))
  nov-mode()
  set-auto-mode-0(nov-mode nil)
  set-auto-mode()
  normal-mode(t)
  after-find-file(nil t)
  find-file-noselect-1(#<buffer 计算机是怎样跑起来的.epub<Books>> "~/Org/Wiki/Computer Technology/Programming/Data/Books/计算机是怎样跑起来的.epub" nil nil "~/Org/Wiki/Computer Technology/Programming/Data/Books/计算机是怎样跑起来的.epub" (7090074 2053))
  find-file-noselect("/home/stardiviner/Org/Wiki/Computer Technology/Programming/Data/Books/计算机是怎样跑起来的.epub" nil nil nil)
  find-file("/home/stardiviner/Org/Wiki/Computer Technology/Programming/Data/Books/计算机是怎样跑起来的.epub")
  funcall(find-file "/home/stardiviner/Org/Wiki/Computer Technology/Programming/Data/Books/计算机是怎样跑起来的.epub")
  (cond ((and (stringp cmd) (not (string-match "^\\s-*$" cmd))) (while (string-match "['\"]%s['\"]" cmd) (setq cmd (replace-match "%s" t t cmd))) (setq cmd (replace-regexp-in-string "%s" (shell-quote-argument (convert-standard-filename file)) cmd nil t)) (let ((save-match-data-internal (match-data))) (unwind-protect (progn (let ((match-index 1) (number-of-groups (- (/ (length link-match-data) 2) 1))) (set-match-data link-match-data) (while (<= match-index number-of-groups) (let ((regex (concat "%" (number-to-string match-index))) (replace-with (match-string match-index dlink))) (while (string-match regex cmd) (setq cmd (replace-match replace-with t t cmd)))) (setq match-index (+ match-index 1))))) (set-match-data save-match-data-internal 'evaporate))) (let ((wconfig (current-window-configuration))) (unwind-protect (progn (message "Running %s...done" cmd) (start-process-shell-command cmd nil cmd) (and (boundp 'org-wait) (numberp org-wait) (sit-for org-wait))) (set-window-configuration wconfig)))) ((or (stringp cmd) (eq cmd 'emacs)) (funcall (cdr (assq 'file org-link-frame-setup)) file) (widen) (cond (line (org-goto-line line) (if (derived-mode-p 'org-mode) (progn (org-reveal)))) (search (condition-case err (org-link-search search) (error (funcall save-position-maybe) (error (nth 1 err))))))) ((functionp cmd) (let ((save-match-data-internal (match-data))) (unwind-protect (progn (set-match-data link-match-data) (condition-case nil (funcall cmd file link) ((debug wrong-number-of-arguments wrong-type-argument invalid-function) (user-error "Please see Org News for version 9.0 about `org-file-apps'--Lisp error: %S" cmd)))) (set-match-data save-match-data-internal 'evaporate)))) ((consp cmd) (user-error "Please see Org News for version 9.0 about `org-file-apps'--Error: Deprecated usage of %S" cmd)) (t (funcall (cdr (assq 'file org-link-frame-setup)) file)))
  (let* ((file (if (equal path "") buffer-file-name (substitute-in-file-name (expand-file-name path)))) (file-apps (append org-file-apps (org-default-apps))) (apps (cl-remove-if 'org-file-apps-entry-match-against-dlink-p file-apps)) (apps-dlink (cl-remove-if-not 'org-file-apps-entry-match-against-dlink-p file-apps)) (remp (and (assq 'remote apps) (org-file-remote-p file))) (dirp (if remp nil (file-directory-p file))) (file (if (and dirp org-open-directory-means-index-dot-org) (concat (file-name-as-directory file) "index.org") file)) (a-m-a-p (assq 'auto-mode apps)) (dfile (downcase file)) (link (cond (line (concat file "::" (number-to-string line))) (search (concat file "::" search)) (t file))) (dlink (downcase link)) (ext (and (string-match "\\`.*?\\.\\([a-zA-Z0-9]+\\(\\.gz\\)?\\)\\'" dfile) (match-string 1 dfile))) (save-position-maybe (let ((old-buffer (current-buffer)) (old-pos (point)) (old-mode major-mode)) (function (lambda nil (and (derived-mode-p 'org-mode) (eq old-mode 'org-mode) (or (not (eq old-buffer (current-buffer))) (not (eq old-pos (point)))) (org-mark-ring-push old-pos old-buffer)))))) cmd link-match-data) (cond ((member in-emacs '((16) system)) (setq cmd (cdr (assq 'system apps)))) (in-emacs (setq cmd 'emacs)) (t (setq cmd (or (and remp (cdr (assq 'remote apps))) (and dirp (cdr (assq 'directory apps))) (let ((match (assoc-default dlink apps-dlink 'string-match))) (if match (progn (setq link-match-data (match-data)) match) (progn (setq in-emacs (or in-emacs line search)) nil))) (assoc-default dfile (org-apps-regexp-alist apps a-m-a-p) 'string-match) (cdr (assoc ext apps)) (cdr (assq t apps)))))) (if (eq cmd 'system) (progn (setq cmd (cdr (assq 'system apps))))) (if (eq cmd 'default) (progn (setq cmd (cdr (assoc t apps))))) (if (eq cmd 'mailcap) (progn (require 'mailcap) (mailcap-parse-mailcaps) (let* ((mime-type (mailcap-extension-to-mime (or ext ""))) (command (mailcap-mime-info mime-type))) (if (stringp command) (setq cmd command) (setq cmd 'emacs))))) (if (and (not (eq cmd 'emacs)) (not (file-exists-p file)) (not org-open-non-existing-files)) (progn (user-error "No such file: %s" file))) (cond ((and (stringp cmd) (not (string-match "^\\s-*$" cmd))) (while (string-match "['\"]%s['\"]" cmd) (setq cmd (replace-match "%s" t t cmd))) (setq cmd (replace-regexp-in-string "%s" (shell-quote-argument (convert-standard-filename file)) cmd nil t)) (let ((save-match-data-internal (match-data))) (unwind-protect (progn (let ((match-index 1) (number-of-groups (- (/ (length link-match-data) 2) 1))) (set-match-data link-match-data) (while (<= match-index number-of-groups) (let ((regex (concat "%" (number-to-string match-index))) (replace-with (match-string match-index dlink))) (while (string-match regex cmd) (setq cmd (replace-match replace-with t t cmd)))) (setq match-index (+ match-index 1))))) (set-match-data save-match-data-internal 'evaporate))) (let ((wconfig (current-window-configuration))) (unwind-protect (progn (message "Running %s...done" cmd) (start-process-shell-command cmd nil cmd) (and (boundp 'org-wait) (numberp org-wait) (sit-for org-wait))) (set-window-configuration wconfig)))) ((or (stringp cmd) (eq cmd 'emacs)) (funcall (cdr (assq 'file org-link-frame-setup)) file) (widen) (cond (line (org-goto-line line) (if (derived-mode-p 'org-mode) (progn (org-reveal)))) (search (condition-case err (org-link-search search) (error (funcall save-position-maybe) (error (nth 1 err))))))) ((functionp cmd) (let ((save-match-data-internal (match-data))) (unwind-protect (progn (set-match-data link-match-data) (condition-case nil (funcall cmd file link) ((debug wrong-number-of-arguments wrong-type-argument invalid-function) (user-error "Please see Org News for version 9.0 about `org-file-apps'--Lisp error: %S" cmd)))) (set-match-data save-match-data-internal 'evaporate)))) ((consp cmd) (user-error "Please see Org News for version 9.0 about `org-file-apps'--Error: Deprecated usage of %S" cmd)) (t (funcall (cdr (assq 'file org-link-frame-setup)) file))) (funcall save-position-maybe))
  org-open-file("Data/Books/计算机是怎样跑起来的.epub" nil)
  apply(org-open-file "Data/Books/计算机是怎样跑起来的.epub" nil nil)
  (if dedicated-function (funcall dedicated-function (concat path (and option (concat "::" option)))) (apply (function org-open-file) path (cond (arg) ((equal app "emacs") 'emacs) ((equal app "sys") 'system)) (cond ((not option) nil) ((string-match-p "\\`[0-9]+\\'" option) (list (string-to-number option))) (t (list nil (org-link-unescape option))))))
  (let* ((option (org-element-property :search-option context)) (app (org-element-property :application context)) (dedicated-function (org-link-get-parameter (if app (concat type "+" app) type) :follow))) (if dedicated-function (funcall dedicated-function (concat path (and option (concat "::" option)))) (apply (function org-open-file) path (cond (arg) ((equal app "emacs") 'emacs) ((equal app "sys") 'system)) (cond ((not option) nil) ((string-match-p "\\`[0-9]+\\'" option) (list (string-to-number option))) (t (list nil (org-link-unescape option)))))))
  (if (string-match "[*?{]" (file-name-nondirectory path)) (dired path) (let* ((option (org-element-property :search-option context)) (app (org-element-property :application context)) (dedicated-function (org-link-get-parameter (if app (concat type "+" app) type) :follow))) (if dedicated-function (funcall dedicated-function (concat path (and option (concat "::" option)))) (apply (function org-open-file) path (cond (arg) ((equal app "emacs") 'emacs) ((equal app "sys") 'system)) (cond ((not option) nil) ((string-match-p "\\`[0-9]+\\'" option) (list (string-to-number option))) (t (list nil (org-link-unescape option))))))))
  (cond ((equal type "file") (if (string-match "[*?{]" (file-name-nondirectory path)) (dired path) (let* ((option (org-element-property :search-option context)) (app (org-element-property :application context)) (dedicated-function (org-link-get-parameter (if app (concat type "+" app) type) :follow))) (if dedicated-function (funcall dedicated-function (concat path (and option (concat "::" option)))) (apply (function org-open-file) path (cond (arg) ((equal app "emacs") 'emacs) ((equal app "sys") 'system)) (cond ((not option) nil) ((string-match-p "\\`[0-9]+\\'" option) (list (string-to-number option))) (t (list nil (org-link-unescape option))))))))) ((functionp (org-link-get-parameter type :follow)) (funcall (org-link-get-parameter type :follow) path)) ((member type '("coderef" "custom-id" "fuzzy" "radio")) (if (run-hook-with-args-until-success 'org-open-link-functions path) nil (if (not arg) (org-mark-ring-push) (switch-to-buffer-other-window (org-get-buffer-for-internal-link (current-buffer)))) (let ((destination (save-excursion (save-restriction (widen) (if (equal type "radio") (org-search-radio-target (org-element-property :path context)) (org-link-search (if (member type '("custom-id" "coderef")) (org-element-property :raw-link context) path) (and (equal type "fuzzy") (+ 2 (org-element-property :begin context))))) (point))))) (if (and (<= (point-min) destination) (>= (point-max) destination)) nil (widen)) (goto-char destination)))) (t (browse-url-at-point)))
  (save-current-buffer (set-buffer (or reference-buffer (current-buffer))) (cond ((equal type "file") (if (string-match "[*?{]" (file-name-nondirectory path)) (dired path) (let* ((option (org-element-property :search-option context)) (app (org-element-property :application context)) (dedicated-function (org-link-get-parameter (if app (concat type "+" app) type) :follow))) (if dedicated-function (funcall dedicated-function (concat path (and option (concat "::" option)))) (apply (function org-open-file) path (cond (arg) ((equal app "emacs") 'emacs) ((equal app "sys") 'system)) (cond ((not option) nil) ((string-match-p "\\`[0-9]+\\'" option) (list (string-to-number option))) (t (list nil (org-link-unescape option))))))))) ((functionp (org-link-get-parameter type :follow)) (funcall (org-link-get-parameter type :follow) path)) ((member type '("coderef" "custom-id" "fuzzy" "radio")) (if (run-hook-with-args-until-success 'org-open-link-functions path) nil (if (not arg) (org-mark-ring-push) (switch-to-buffer-other-window (org-get-buffer-for-internal-link (current-buffer)))) (let ((destination (save-excursion (save-restriction (widen) (if (equal type "radio") (org-search-radio-target (org-element-property :path context)) (org-link-search (if (member type '("custom-id" "coderef")) (org-element-property :raw-link context) path) (and (equal type "fuzzy") (+ 2 (org-element-property :begin context))))) (point))))) (if (and (<= (point-min) destination) (>= (point-max) destination)) nil (widen)) (goto-char destination)))) (t (browse-url-at-point))))
  (let ((type (org-element-property :type context)) (path (org-link-unescape (org-element-property :path context)))) (save-current-buffer (set-buffer (or reference-buffer (current-buffer))) (cond ((equal type "file") (if (string-match "[*?{]" (file-name-nondirectory path)) (dired path) (let* ((option (org-element-property :search-option context)) (app (org-element-property :application context)) (dedicated-function (org-link-get-parameter (if app (concat type "+" app) type) :follow))) (if dedicated-function (funcall dedicated-function (concat path (and option (concat "::" option)))) (apply (function org-open-file) path (cond (arg) ((equal app "emacs") 'emacs) ((equal app "sys") 'system)) (cond ((not option) nil) ((string-match-p "\\`[0-9]+\\'" option) (list (string-to-number option))) (t (list nil (org-link-unescape option))))))))) ((functionp (org-link-get-parameter type :follow)) (funcall (org-link-get-parameter type :follow) path)) ((member type '("coderef" "custom-id" "fuzzy" "radio")) (if (run-hook-with-args-until-success 'org-open-link-functions path) nil (if (not arg) (org-mark-ring-push) (switch-to-buffer-other-window (org-get-buffer-for-internal-link (current-buffer)))) (let ((destination (save-excursion (save-restriction (widen) (if (equal type "radio") (org-search-radio-target (org-element-property :path context)) (org-link-search (if (member type '("custom-id" "coderef")) (org-element-property :raw-link context) path) (and (equal type "fuzzy") (+ 2 (org-element-property :begin context))))) (point))))) (if (and (<= (point-min) destination) (>= (point-max) destination)) nil (widen)) (goto-char destination)))) (t (browse-url-at-point)))))
  (cond ((memq type '(headline inlinetask)) (org-match-line org-complex-heading-regexp) (if (and (match-beginning 5) (>= (point) (match-beginning 5)) (< (point) (match-end 5))) (org-tags-view arg (substring (match-string 5) 0 -1)) (let* ((val (org-offer-links-in-entry (current-buffer) (point) arg))) (if (consp val) (let* ((x211 (car val))) (if (null x211) (progn (require 'org-attach) (org-attach-reveal 'if-exists)) (let* ((x213 (cdr val))) (let ((links-end x213) (links x211)) (let ((--dolist-tail-- (if (stringp links) (list links) links))) (while --dolist-tail-- (let ((link (car --dolist-tail--))) (search-forward link nil links-end) (goto-char (match-beginning 0)) (org-open-at-point) (setq --dolist-tail-- (cdr --dolist-tail--))))))))) nil)))) ((or (eq type 'footnote-reference) (and (eq type 'footnote-definition) (save-excursion (skip-chars-forward " \11") (let ((begin (org-element-property :contents-begin context))) (if begin (< (point) begin) (= (org-element-property :post-affiliated context) (line-beginning-position))))))) (org-footnote-action)) ((memq type '(footnote-definition headline inlinetask nil)) (call-interactively (function org-open-at-point-global))) ((and (eq type 'clock) value (>= (point) (org-element-property :begin value)) (<= (point) (org-element-property :end value))) (org-follow-timestamp-link)) ((>= (point) (save-excursion (goto-char (org-element-property :end context)) (skip-chars-backward " \11") (point))) (user-error "No link found")) ((eq type 'timestamp) (org-follow-timestamp-link)) ((eq type 'link) (let ((type (org-element-property :type context)) (path (org-link-unescape (org-element-property :path context)))) (save-current-buffer (set-buffer (or reference-buffer (current-buffer))) (cond ((equal type "file") (if (string-match "[*?{]" (file-name-nondirectory path)) (dired path) (let* ((option (org-element-property :search-option context)) (app (org-element-property :application context)) (dedicated-function (org-link-get-parameter (if app (concat type "+" app) type) :follow))) (if dedicated-function (funcall dedicated-function (concat path (and option (concat "::" option)))) (apply (function org-open-file) path (cond (arg) ((equal app "emacs") 'emacs) ((equal app "sys") 'system)) (cond ((not option) nil) ((string-match-p "\\`[0-9]+\\'" option) (list (string-to-number option))) (t (list nil (org-link-unescape option))))))))) ((functionp (org-link-get-parameter type :follow)) (funcall (org-link-get-parameter type :follow) path)) ((member type '("coderef" "custom-id" "fuzzy" "radio")) (if (run-hook-with-args-until-success 'org-open-link-functions path) nil (if (not arg) (org-mark-ring-push) (switch-to-buffer-other-window (org-get-buffer-for-internal-link (current-buffer)))) (let ((destination (save-excursion (save-restriction (widen) (if (equal type "radio") (org-search-radio-target (org-element-property :path context)) (org-link-search (if (member type '("custom-id" "coderef")) (org-element-property :raw-link context) path) (and (equal type "fuzzy") (+ 2 (org-element-property :begin context))))) (point))))) (if (and (<= (point-min) destination) (>= (point-max) destination)) nil (widen)) (goto-char destination)))) (t (browse-url-at-point)))))) (t (user-error "No link found")))
  (let* ((context (org-element-lineage (org-element-context) '(clock footnote-definition footnote-reference headline inlinetask link timestamp) t)) (type (org-element-type context)) (value (org-element-property :value context))) (cond ((memq type '(headline inlinetask)) (org-match-line org-complex-heading-regexp) (if (and (match-beginning 5) (>= (point) (match-beginning 5)) (< (point) (match-end 5))) (org-tags-view arg (substring (match-string 5) 0 -1)) (let* ((val (org-offer-links-in-entry (current-buffer) (point) arg))) (if (consp val) (let* ((x211 (car val))) (if (null x211) (progn (require 'org-attach) (org-attach-reveal 'if-exists)) (let* ((x213 (cdr val))) (let ((links-end x213) (links x211)) (let ((--dolist-tail-- (if (stringp links) (list links) links))) (while --dolist-tail-- (let ((link (car --dolist-tail--))) (search-forward link nil links-end) (goto-char (match-beginning 0)) (org-open-at-point) (setq --dolist-tail-- (cdr --dolist-tail--))))))))) nil)))) ((or (eq type 'footnote-reference) (and (eq type 'footnote-definition) (save-excursion (skip-chars-forward " \11") (let ((begin (org-element-property :contents-begin context))) (if begin (< (point) begin) (= (org-element-property :post-affiliated context) (line-beginning-position))))))) (org-footnote-action)) ((memq type '(footnote-definition headline inlinetask nil)) (call-interactively (function org-open-at-point-global))) ((and (eq type 'clock) value (>= (point) (org-element-property :begin value)) (<= (point) (org-element-property :end value))) (org-follow-timestamp-link)) ((>= (point) (save-excursion (goto-char (org-element-property :end context)) (skip-chars-backward " \11") (point))) (user-error "No link found")) ((eq type 'timestamp) (org-follow-timestamp-link)) ((eq type 'link) (let ((type (org-element-property :type context)) (path (org-link-unescape (org-element-property :path context)))) (save-current-buffer (set-buffer (or reference-buffer (current-buffer))) (cond ((equal type "file") (if (string-match "[*?{]" (file-name-nondirectory path)) (dired path) (let* ((option (org-element-property :search-option context)) (app (org-element-property :application context)) (dedicated-function (org-link-get-parameter (if app (concat type "+" app) type) :follow))) (if dedicated-function (funcall dedicated-function (concat path (and option (concat "::" option)))) (apply (function org-open-file) path (cond (arg) ((equal app "emacs") 'emacs) ((equal app "sys") 'system)) (cond ((not option) nil) ((string-match-p "\\`[0-9]+\\'" option) (list (string-to-number option))) (t (list nil (org-link-unescape option))))))))) ((functionp (org-link-get-parameter type :follow)) (funcall (org-link-get-parameter type :follow) path)) ((member type '("coderef" "custom-id" "fuzzy" "radio")) (if (run-hook-with-args-until-success 'org-open-link-functions path) nil (if (not arg) (org-mark-ring-push) (switch-to-buffer-other-window (org-get-buffer-for-internal-link (current-buffer)))) (let ((destination (save-excursion (save-restriction (widen) (if (equal type "radio") (org-search-radio-target (org-element-property :path context)) (org-link-search (if (member type '("custom-id" "coderef")) (org-element-property :raw-link context) path) (and (equal type "fuzzy") (+ 2 (org-element-property :begin context))))) (point))))) (if (and (<= (point-min) destination) (>= (point-max) destination)) nil (widen)) (goto-char destination)))) (t (browse-url-at-point)))))) (t (user-error "No link found"))))
  (if (run-hook-with-args-until-success 'org-open-at-point-functions) nil (let* ((context (org-element-lineage (org-element-context) '(clock footnote-definition footnote-reference headline inlinetask link timestamp) t)) (type (org-element-type context)) (value (org-element-property :value context))) (cond ((memq type '(headline inlinetask)) (org-match-line org-complex-heading-regexp) (if (and (match-beginning 5) (>= (point) (match-beginning 5)) (< (point) (match-end 5))) (org-tags-view arg (substring (match-string 5) 0 -1)) (let* ((val (org-offer-links-in-entry (current-buffer) (point) arg))) (if (consp val) (let* ((x211 (car val))) (if (null x211) (progn (require 'org-attach) (org-attach-reveal 'if-exists)) (let* ((x213 (cdr val))) (let ((links-end x213) (links x211)) (let ((--dolist-tail-- (if (stringp links) (list links) links))) (while --dolist-tail-- (let ((link (car --dolist-tail--))) (search-forward link nil links-end) (goto-char (match-beginning 0)) (org-open-at-point) (setq --dolist-tail-- (cdr --dolist-tail--))))))))) nil)))) ((or (eq type 'footnote-reference) (and (eq type 'footnote-definition) (save-excursion (skip-chars-forward " \11") (let ((begin (org-element-property :contents-begin context))) (if begin (< (point) begin) (= (org-element-property :post-affiliated context) (line-beginning-position))))))) (org-footnote-action)) ((memq type '(footnote-definition headline inlinetask nil)) (call-interactively (function org-open-at-point-global))) ((and (eq type 'clock) value (>= (point) (org-element-property :begin value)) (<= (point) (org-element-property :end value))) (org-follow-timestamp-link)) ((>= (point) (save-excursion (goto-char (org-element-property :end context)) (skip-chars-backward " \11") (point))) (user-error "No link found")) ((eq type 'timestamp) (org-follow-timestamp-link)) ((eq type 'link) (let ((type (org-element-property :type context)) (path (org-link-unescape (org-element-property :path context)))) (save-current-buffer (set-buffer (or reference-buffer (current-buffer))) (cond ((equal type "file") (if (string-match "[*?{]" (file-name-nondirectory path)) (dired path) (let* ((option (org-element-property :search-option context)) (app (org-element-property :application context)) (dedicated-function (org-link-get-parameter (if app (concat type "+" app) type) :follow))) (if dedicated-function (funcall dedicated-function (concat path (and option (concat "::" option)))) (apply (function org-open-file) path (cond (arg) ((equal app "emacs") 'emacs) ((equal app "sys") 'system)) (cond ((not option) nil) ((string-match-p "\\`[0-9]+\\'" option) (list (string-to-number option))) (t (list nil (org-link-unescape option))))))))) ((functionp (org-link-get-parameter type :follow)) (funcall (org-link-get-parameter type :follow) path)) ((member type '("coderef" "custom-id" "fuzzy" "radio")) (if (run-hook-with-args-until-success 'org-open-link-functions path) nil (if (not arg) (org-mark-ring-push) (switch-to-buffer-other-window (org-get-buffer-for-internal-link (current-buffer)))) (let ((destination (save-excursion (save-restriction (widen) (if (equal type "radio") (org-search-radio-target (org-element-property :path context)) (org-link-search (if (member type '("custom-id" "coderef")) (org-element-property :raw-link context) path) (and (equal type "fuzzy") (+ 2 (org-element-property :begin context))))) (point))))) (if (and (<= (point-min) destination) (>= (point-max) destination)) nil (widen)) (goto-char destination)))) (t (browse-url-at-point)))))) (t (user-error "No link found")))))
  (if (call-interactively 'org-babel-open-src-block-result) nil (org-load-modules-maybe) (setq org-window-config-before-follow-link (current-window-configuration)) (org-remove-occur-highlights nil nil t) (if (run-hook-with-args-until-success 'org-open-at-point-functions) nil (let* ((context (org-element-lineage (org-element-context) '(clock footnote-definition footnote-reference headline inlinetask link timestamp) t)) (type (org-element-type context)) (value (org-element-property :value context))) (cond ((memq type '(headline inlinetask)) (org-match-line org-complex-heading-regexp) (if (and (match-beginning 5) (>= (point) (match-beginning 5)) (< (point) (match-end 5))) (org-tags-view arg (substring (match-string 5) 0 -1)) (let* ((val (org-offer-links-in-entry (current-buffer) (point) arg))) (if (consp val) (let* ((x211 (car val))) (if (null x211) (progn (require 'org-attach) (org-attach-reveal 'if-exists)) (let* ((x213 (cdr val))) (let ((links-end x213) (links x211)) (let ((--dolist-tail-- (if (stringp links) (list links) links))) (while --dolist-tail-- (let ((link (car --dolist-tail--))) (search-forward link nil links-end) (goto-char (match-beginning 0)) (org-open-at-point) (setq --dolist-tail-- (cdr --dolist-tail--))))))))) nil)))) ((or (eq type 'footnote-reference) (and (eq type 'footnote-definition) (save-excursion (skip-chars-forward " \11") (let ((begin (org-element-property :contents-begin context))) (if begin (< (point) begin) (= (org-element-property :post-affiliated context) (line-beginning-position))))))) (org-footnote-action)) ((memq type '(footnote-definition headline inlinetask nil)) (call-interactively (function org-open-at-point-global))) ((and (eq type 'clock) value (>= (point) (org-element-property :begin value)) (<= (point) (org-element-property :end value))) (org-follow-timestamp-link)) ((>= (point) (save-excursion (goto-char (org-element-property :end context)) (skip-chars-backward " \11") (point))) (user-error "No link found")) ((eq type 'timestamp) (org-follow-timestamp-link)) ((eq type 'link) (let ((type (org-element-property :type context)) (path (org-link-unescape (org-element-property :path context)))) (save-current-buffer (set-buffer (or reference-buffer (current-buffer))) (cond ((equal type "file") (if (string-match "[*?{]" (file-name-nondirectory path)) (dired path) (let* ((option (org-element-property :search-option context)) (app (org-element-property :application context)) (dedicated-function (org-link-get-parameter (if app (concat type "+" app) type) :follow))) (if dedicated-function (funcall dedicated-function (concat path (and option (concat "::" option)))) (apply (function org-open-file) path (cond (arg) ((equal app "emacs") 'emacs) ((equal app "sys") 'system)) (cond ((not option) nil) ((string-match-p "\\`[0-9]+\\'" option) (list (string-to-number option))) (t (list nil (org-link-unescape option))))))))) ((functionp (org-link-get-parameter type :follow)) (funcall (org-link-get-parameter type :follow) path)) ((member type '("coderef" "custom-id" "fuzzy" "radio")) (if (run-hook-with-args-until-success 'org-open-link-functions path) nil (if (not arg) (org-mark-ring-push) (switch-to-buffer-other-window (org-get-buffer-for-internal-link (current-buffer)))) (let ((destination (save-excursion (save-restriction (widen) (if (equal type "radio") (org-search-radio-target (org-element-property :path context)) (org-link-search (if (member type '("custom-id" "coderef")) (org-element-property :raw-link context) path) (and (equal type "fuzzy") (+ 2 (org-element-property :begin context))))) (point))))) (if (and (<= (point-min) destination) (>= (point-max) destination)) nil (widen)) (goto-char destination)))) (t (browse-url-at-point)))))) (t (user-error "No link found"))))) (run-hook-with-args 'org-follow-link-hook))
  org-open-at-point(nil)
  funcall-interactively(org-open-at-point nil)
  call-interactively(org-open-at-point nil nil)
  command-execute(org-open-at-point)

This error not occurs on all EPUB files, just some EPUB files.
I will upload a test epub file here so you can test it (because can't upload EPUB file, so I compressed it to ZIP, unzip it please).

test.zip

Info-like continuous search [feature request]

In Info-mode, you can C-s and search for anything through the whole document. What I mean is that you do not have to be present in an Info node containing the string you are searching for.. If Info does not find your search string in the current node, it will try searching in the next node, and so on.

Can something like that be done for searching in epubs? I can be in the TOC buffer of an ebook and starting searching with C-s.. nov.el should then try to find that term successively in the whole ebook.

Thanks!

Display each section in a buffer

Expected Behavior

Each section is displayed in a buffer, and the user can advance by section in addition to by chapter.

This would be similar to how Info treats nodes.

Actual Behavior

Only chapters can be displayed in a buffer.

Navigating from TOC to chapters, navigation skipping chapters

I am having the same problem as in #13 with some additional features. In all epub files I have tried, I can not enter the chapter with enter. The only way I could see something else than the TOC, is to press 'N'.

You can try this book https://www.gutenberg.org/ebooks/1342 . Both epub versions available (with or without images) cause emacs to complain of the same thing. In addition, first press of 'N' shows the toc with header text and next 'N' shows chapter 7. Consecutive presses of 'N' jump to chapters 11, 17, 20, 25, 30, 35, 40, ...

Would be nice to accept more ebooks

Finding a lot of ebooks which are readable by ereader mode but not nov.el, but prefer nov.el overall.

Happy to provide an example file, if that helps.

Generally error is of the form:

File mode specification error: (error Unique identifier not found by its name: ...)
Is it possible to recover gracefully in this case?

If not, can we at least not open the zip file as a binary file once parsing fails?

Enhancement: remember TOC file line position when returning to TOC

Currently hitting t when in the main text of an EPUB brings up TOC with the point at the first char. Scrolling to, say, line 10 of the TOC, hitting Enter, opens whatever chapter line 10 was referring. Hitting t again opens TOC at first char of the file again, instead of the previous position at line 10, a bit disorienting if the TOC is large.

(wrong-type-argument stringp nil) when opening a file

Hello. When opening any epub file i'm getting error with this stacktrace:

Debugger entered--Lisp error: (wrong-type-argument stringp nil)
  file-name-nondirectory(nil)
  file-name-extension(nil)
  (string= (file-name-extension buffer-file-name) "css")
  (if (string= (file-name-extension buffer-file-name) "css") (progn (flycheck-select-checker (quote css-csslint))))
  (lambda nil (if (string= (file-name-extension buffer-file-name) "css") (progn (flycheck-select-checker (quote css-csslint)))))()
  run-hooks(find-file-hook)
  after-find-file(nil t)
  find-file-noselect-1(#<buffer migrating-java-to-the-cloud.epub> "~/Downloads/migrating-java-to-the-cloud.epub" nil nil "~/Downloads/migrating-java-to-the-cloud.epub" (6688817 2050))
  find-file-noselect("/home/ivan/Downloads/migrating-java-to-the-cloud.epub" nil nil nil)
  find-file("/home/ivan/Downloads/migrating-java-to-the-cloud.epub")
  #[257 "\304\305�!!r\306\307\310\311\312�!\313\"\314$\216\315�@\316\"\210	\205�

The buffer is actually opening but emacs not switching to it(just prints exception), i can only switch to buffer manually. Everything else work as intended

Keybinding to switch to archive-mode

Once nice feature in emacs is the ability to edit zip files directly. I use this e.g. to edit the css of an epub. But when activating nov mode for epub files, there is no longer a simple way of turning on archive mode for the buffer. I suggest to add a keybinding to nov to switch into archive-mode for the file.

Encoding issue?

Did anybody encounter this issue? Looks like it fails to encode apostrophe and space etc. I am using Arch Linux with Emacs 25.3.

I didn鈥檛 find the last line quite satisfying, so for several weeks I reflected on it, questioned it, wrestled with it, until one day the answer I was looking for came to me: 鈥淚f you want to be happy for a lifetime, give yourself to others.鈥

error "Unique identifier not found by its name: ISBN"

This issue is specific to my copy of SICP, which you can download here. On emacs -q on this file in archive mode. M-x nov-mode RET fails with the following error:

Debugger entered--Lisp error: (error "Unique identifier not found by its name: ISBN")
  signal(error ("Unique identifier not found by its name: ISBN"))
  error("Unique identifier not found by its name: %s" "ISBN")
  (progn (error "Unique identifier not found by its name: %s" name))
  (if (not id) (progn (error "Unique identifier not found by its name: %s" name)))
  (let* ((name (nov-content-unique-identifier-name content)) (selector (format "package>metadata>identifier[id='%s']" (regexp-quote name))) (id (car (esxml-node-children (esxml-query selector content))))) (if (not id) (progn (error "Unique identifier not found by its name: %s" name))) (intern id))
  nov-content-unique-identifier((package ((unique-identifier . "ISBN") (version . "2.0")) (metadata nil (title nil "Structure and Interpretation of Computer Programs") (creator nil "Harold Abelson and Gerald Jay Sussman with Julie Sussman") (identifier ((scheme . "ISBN")) "0-262-01153-0") (rights nil "Creative Commons Attribution-Noncommercial 3.0 Unported License.") (language nil "en-US") (source nil "http://mitpress.mit.edu/sicp/full-text/book/book.html") (publisher nil "MIT Press") (meta ((name . "cover") (content . "cover.jpg")))) (manifest nil (item ((id . "ncx") (href . "toc.ncx") (media-type . "application/x-dtbncx+xml"))) (item ((id . "book") (href . "book.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-1") (href . "book-Z-H-1.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-2") (href . "book-Z-H-2.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-3") (href . "book-Z-H-3.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-5") (href . "book-Z-H-5.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-6") (href . "book-Z-H-6.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-7") (href . "book-Z-H-7.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-8") (href . "book-Z-H-8.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-9") (href . "book-Z-H-9.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-10") (href . "book-Z-H-10.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-11") (href . "book-Z-H-11.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-12") (href . "book-Z-H-12.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-13") (href . "book-Z-H-13.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-14") (href . "book-Z-H-14.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-15") (href . "book-Z-H-15.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-16") (href . "book-Z-H-16.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-17") (href . "book-Z-H-17.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-18") (href . "book-Z-H-18.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-19") (href . "book-Z-H-19.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-20") (href . "book-Z-H-20.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-21") (href . "book-Z-H-21.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-22") (href . "book-Z-H-22.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-23") (href . "book-Z-H-23.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-24") (href . "book-Z-H-24.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-25") (href . "book-Z-H-25.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-26") (href . "book-Z-H-26.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-27") (href . "book-Z-H-27.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-28") (href . "book-Z-H-28.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-29") (href . "book-Z-H-29.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-30") (href . "book-Z-H-30.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-31") (href . "book-Z-H-31.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-32") (href . "book-Z-H-32.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-33") (href . "book-Z-H-33.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-34") (href . "book-Z-H-34.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-35") (href . "book-Z-H-35.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-36") (href . "book-Z-H-36.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-37") (href . "book-Z-H-37.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-38") (href . "book-Z-H-38.html") (media-type . "application/xhtml+xml"))) (item ((id . "css") (href . "stylesheet.css") (media-type . "text/css"))) (comment nil " Images ") (item ((id . "ch1-Z-G-1") (href . "images/ch1-Z-G-1.gif") (media-type . "image/gif"))) (item ((id . "ch1-Z-G-10") (href . "images/ch1-Z-G-10.gif") (media-type . "image/gif"))) (item ((id . "ch1-Z-G-12") (href . "images/ch1-Z-G-12.gif") (media-type . "image/gif"))) (item ((id . "ch1-Z-G-13") (href . "images/ch1-Z-G-13.gif") (media-type . "image/gif"))) (item ((id . "ch1-Z-G-17") (href . "images/ch1-Z-G-17.gif") (media-type . "image/gif"))) (item ((id . "ch1-Z-G-19") (href . "images/ch1-Z-G-19.gif") (media-type . "image/gif"))) (item ((id . "ch1-Z-G-2") (href . "images/ch1-Z-G-2.gif") (media-type . "image/gif"))) ...) (spine ((toc . "ncx")) (itemref ((idref . "book-Z-H-1") (linear . "yes"))) (itemref ((idref . "book-Z-H-2") (linear . "yes"))) (itemref ((idref . "book-Z-H-3") (linear . "yes"))) (itemref ((idref . "book-Z-H-5") (linear . "yes"))) (itemref ((idref . "book-Z-H-6") (linear . "yes"))) (itemref ((idref . "book-Z-H-7") (linear . "yes"))) (itemref ((idref . "book-Z-H-8") (linear . "yes"))) (itemref ((idref . "book-Z-H-9") (linear . "yes"))) (itemref ((idref . "book-Z-H-10") (linear . "yes"))) (itemref ((idref . "book-Z-H-11") (linear . "yes"))) (itemref ((idref . "book-Z-H-12") (linear . "yes"))) (itemref ((idref . "book-Z-H-13") (linear . "yes"))) (itemref ((idref . "book-Z-H-14") (linear . "yes"))) (itemref ((idref . "book-Z-H-15") (linear . "yes"))) (itemref ((idref . "book-Z-H-16") (linear . "yes"))) (itemref ((idref . "book-Z-H-17") (linear . "yes"))) (itemref ((idref . "book-Z-H-18") (linear . "yes"))) (itemref ((idref . "book-Z-H-19") (linear . "yes"))) (itemref ((idref . "book-Z-H-20") (linear . "yes"))) (itemref ((idref . "book-Z-H-21") (linear . "yes"))) (itemref ((idref . "book-Z-H-22") (linear . "yes"))) (itemref ((idref . "book-Z-H-23") (linear . "yes"))) (itemref ((idref . "book-Z-H-24") (linear . "yes"))) (itemref ((idref . "book-Z-H-25") (linear . "yes"))) (itemref ((idref . "book-Z-H-26") (linear . "yes"))) (itemref ((idref . "book-Z-H-27") (linear . "yes"))) (itemref ((idref . "book-Z-H-28") (linear . "yes"))) (itemref ((idref . "book-Z-H-29") (linear . "yes"))) (itemref ((idref . "book-Z-H-30") (linear . "yes"))) (itemref ((idref . "book-Z-H-31") (linear . "yes"))) (itemref ((idref . "book-Z-H-32") (linear . "yes"))) (itemref ((idref . "book-Z-H-33") (linear . "yes"))) (itemref ((idref . "book-Z-H-34") (linear . "yes"))) (itemref ((idref . "book-Z-H-35") (linear . "yes"))) (itemref ((idref . "book-Z-H-36") (linear . "yes"))) (itemref ((idref . "book-Z-H-37") (linear . "yes"))) (itemref ((idref . "book-Z-H-38") (linear . "yes")))) (guide nil (reference ((href . "book.html") (type . "cover") (title . "Cover"))))))
  (let* ((identifier (nov-content-unique-identifier content)) (candidates (mapcar (function (lambda (node) (cons (esxml-node-tag node) (car ...)))) (esxml-query-all "package>metadata>*" content))) (required (mapcar (function (lambda (tag) (let (...) (if ... ...) (cons tag candidate)))) nov-required-metadata-tags)) (optional (mapcar (function (lambda (tag) (cons tag (cdr ...)))) nov-optional-metadata-tags))) (append (list (cons (quote identifier) identifier)) required optional))
  nov-content-metadata((package ((unique-identifier . "ISBN") (version . "2.0")) (metadata nil (title nil "Structure and Interpretation of Computer Programs") (creator nil "Harold Abelson and Gerald Jay Sussman with Julie Sussman") (identifier ((scheme . "ISBN")) "0-262-01153-0") (rights nil "Creative Commons Attribution-Noncommercial 3.0 Unported License.") (language nil "en-US") (source nil "http://mitpress.mit.edu/sicp/full-text/book/book.html") (publisher nil "MIT Press") (meta ((name . "cover") (content . "cover.jpg")))) (manifest nil (item ((id . "ncx") (href . "toc.ncx") (media-type . "application/x-dtbncx+xml"))) (item ((id . "book") (href . "book.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-1") (href . "book-Z-H-1.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-2") (href . "book-Z-H-2.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-3") (href . "book-Z-H-3.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-5") (href . "book-Z-H-5.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-6") (href . "book-Z-H-6.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-7") (href . "book-Z-H-7.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-8") (href . "book-Z-H-8.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-9") (href . "book-Z-H-9.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-10") (href . "book-Z-H-10.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-11") (href . "book-Z-H-11.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-12") (href . "book-Z-H-12.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-13") (href . "book-Z-H-13.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-14") (href . "book-Z-H-14.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-15") (href . "book-Z-H-15.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-16") (href . "book-Z-H-16.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-17") (href . "book-Z-H-17.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-18") (href . "book-Z-H-18.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-19") (href . "book-Z-H-19.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-20") (href . "book-Z-H-20.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-21") (href . "book-Z-H-21.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-22") (href . "book-Z-H-22.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-23") (href . "book-Z-H-23.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-24") (href . "book-Z-H-24.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-25") (href . "book-Z-H-25.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-26") (href . "book-Z-H-26.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-27") (href . "book-Z-H-27.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-28") (href . "book-Z-H-28.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-29") (href . "book-Z-H-29.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-30") (href . "book-Z-H-30.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-31") (href . "book-Z-H-31.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-32") (href . "book-Z-H-32.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-33") (href . "book-Z-H-33.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-34") (href . "book-Z-H-34.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-35") (href . "book-Z-H-35.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-36") (href . "book-Z-H-36.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-37") (href . "book-Z-H-37.html") (media-type . "application/xhtml+xml"))) (item ((id . "book-Z-H-38") (href . "book-Z-H-38.html") (media-type . "application/xhtml+xml"))) (item ((id . "css") (href . "stylesheet.css") (media-type . "text/css"))) (comment nil " Images ") (item ((id . "ch1-Z-G-1") (href . "images/ch1-Z-G-1.gif") (media-type . "image/gif"))) (item ((id . "ch1-Z-G-10") (href . "images/ch1-Z-G-10.gif") (media-type . "image/gif"))) (item ((id . "ch1-Z-G-12") (href . "images/ch1-Z-G-12.gif") (media-type . "image/gif"))) (item ((id . "ch1-Z-G-13") (href . "images/ch1-Z-G-13.gif") (media-type . "image/gif"))) (item ((id . "ch1-Z-G-17") (href . "images/ch1-Z-G-17.gif") (media-type . "image/gif"))) (item ((id . "ch1-Z-G-19") (href . "images/ch1-Z-G-19.gif") (media-type . "image/gif"))) (item ((id . "ch1-Z-G-2") (href . "images/ch1-Z-G-2.gif") (media-type . "image/gif"))) ...) (spine ((toc . "ncx")) (itemref ((idref . "book-Z-H-1") (linear . "yes"))) (itemref ((idref . "book-Z-H-2") (linear . "yes"))) (itemref ((idref . "book-Z-H-3") (linear . "yes"))) (itemref ((idref . "book-Z-H-5") (linear . "yes"))) (itemref ((idref . "book-Z-H-6") (linear . "yes"))) (itemref ((idref . "book-Z-H-7") (linear . "yes"))) (itemref ((idref . "book-Z-H-8") (linear . "yes"))) (itemref ((idref . "book-Z-H-9") (linear . "yes"))) (itemref ((idref . "book-Z-H-10") (linear . "yes"))) (itemref ((idref . "book-Z-H-11") (linear . "yes"))) (itemref ((idref . "book-Z-H-12") (linear . "yes"))) (itemref ((idref . "book-Z-H-13") (linear . "yes"))) (itemref ((idref . "book-Z-H-14") (linear . "yes"))) (itemref ((idref . "book-Z-H-15") (linear . "yes"))) (itemref ((idref . "book-Z-H-16") (linear . "yes"))) (itemref ((idref . "book-Z-H-17") (linear . "yes"))) (itemref ((idref . "book-Z-H-18") (linear . "yes"))) (itemref ((idref . "book-Z-H-19") (linear . "yes"))) (itemref ((idref . "book-Z-H-20") (linear . "yes"))) (itemref ((idref . "book-Z-H-21") (linear . "yes"))) (itemref ((idref . "book-Z-H-22") (linear . "yes"))) (itemref ((idref . "book-Z-H-23") (linear . "yes"))) (itemref ((idref . "book-Z-H-24") (linear . "yes"))) (itemref ((idref . "book-Z-H-25") (linear . "yes"))) (itemref ((idref . "book-Z-H-26") (linear . "yes"))) (itemref ((idref . "book-Z-H-27") (linear . "yes"))) (itemref ((idref . "book-Z-H-28") (linear . "yes"))) (itemref ((idref . "book-Z-H-29") (linear . "yes"))) (itemref ((idref . "book-Z-H-30") (linear . "yes"))) (itemref ((idref . "book-Z-H-31") (linear . "yes"))) (itemref ((idref . "book-Z-H-32") (linear . "yes"))) (itemref ((idref . "book-Z-H-33") (linear . "yes"))) (itemref ((idref . "book-Z-H-34") (linear . "yes"))) (itemref ((idref . "book-Z-H-35") (linear . "yes"))) (itemref ((idref . "book-Z-H-36") (linear . "yes"))) (itemref ((idref . "book-Z-H-37") (linear . "yes"))) (itemref ((idref . "book-Z-H-38") (linear . "yes")))) (guide nil (reference ((href . "book.html") (type . "cover") (title . "Cover"))))))
  (setq nov-metadata (nov-content-metadata content))
  (let* ((content (nov-slurp (nov-container-filename nov-temp-dir) t)) (content-file (nov-make-path nov-temp-dir (nov-container-content-filename content))) (work-dir (file-name-directory content-file)) (content (nov-slurp content-file t))) (setq nov-content-file content-file) (setq nov-epub-version (nov-content-version content)) (setq nov-metadata (nov-content-metadata content)) (setq nov-documents (apply (quote vector) (nov-content-files work-dir content))) (setq nov-documents-index 0))
  (let ((delay-mode-hooks t)) (special-mode) (setq major-mode (quote nov-mode)) (setq mode-name "EPUB") (progn (if (get (quote special-mode) (quote mode-class)) (put (quote nov-mode) (quote mode-class) (get (quote special-mode) (quote mode-class)))) (if (keymap-parent nov-mode-map) nil (set-keymap-parent nov-mode-map (current-local-map))) (let ((parent (char-table-parent nov-mode-syntax-table))) (if (and parent (not (eq parent (standard-syntax-table)))) nil (set-char-table-parent nov-mode-syntax-table (syntax-table)))) (if (or (abbrev-table-get nov-mode-abbrev-table :parents) (eq nov-mode-abbrev-table local-abbrev-table)) nil (abbrev-table-put nov-mode-abbrev-table :parents (list local-abbrev-table)))) (use-local-map nov-mode-map) (set-syntax-table nov-mode-syntax-table) (setq local-abbrev-table nov-mode-abbrev-table) (add-hook (quote kill-buffer-hook) (quote nov-clean-up) nil t) (add-hook (quote kill-emacs-hook) (quote nov-clean-up-all)) (add-hook (quote change-major-mode-hook) (quote nov-clean-up) nil t) (if (not buffer-file-name) (progn (error "EPUB must be associated with file"))) (setq nov-temp-dir (make-temp-file "nov-" t ".epub")) (let ((exit-code (nov-unzip-epub nov-temp-dir buffer-file-name))) (if (not (integerp exit-code)) (progn (nov-clean-up) (error "EPUB extraction aborted by signal %s" exit-code))) (if (not (= 0 exit-code)) (progn (nov-clean-up) (error "EPUB extraction failed with exit code %d" exit-code)))) (if (not (nov-epub-valid-p nov-temp-dir)) (progn (nov-clean-up) (error "Invalid EPUB file"))) (let* ((content (nov-slurp (nov-container-filename nov-temp-dir) t)) (content-file (nov-make-path nov-temp-dir (nov-container-content-filename content))) (work-dir (file-name-directory content-file)) (content (nov-slurp content-file t))) (setq nov-content-file content-file) (setq nov-epub-version (nov-content-version content)) (setq nov-metadata (nov-content-metadata content)) (setq nov-documents (apply (quote vector) (nov-content-files work-dir content))) (setq nov-documents-index 0)) (setq buffer-undo-list t) (set-visited-file-name nil t) (let ((place (nov-saved-place (cdr (assq (quote identifier) nov-metadata))))) (if place (let ((index (cdr (assq ... place))) (point (cdr (assq ... place)))) (setq nov-documents-index index) (nov-render-document) (goto-char point)) (nov-render-document))))
  (progn (make-local-variable (quote delay-mode-hooks)) (let ((delay-mode-hooks t)) (special-mode) (setq major-mode (quote nov-mode)) (setq mode-name "EPUB") (progn (if (get (quote special-mode) (quote mode-class)) (put (quote nov-mode) (quote mode-class) (get (quote special-mode) (quote mode-class)))) (if (keymap-parent nov-mode-map) nil (set-keymap-parent nov-mode-map (current-local-map))) (let ((parent (char-table-parent nov-mode-syntax-table))) (if (and parent (not (eq parent ...))) nil (set-char-table-parent nov-mode-syntax-table (syntax-table)))) (if (or (abbrev-table-get nov-mode-abbrev-table :parents) (eq nov-mode-abbrev-table local-abbrev-table)) nil (abbrev-table-put nov-mode-abbrev-table :parents (list local-abbrev-table)))) (use-local-map nov-mode-map) (set-syntax-table nov-mode-syntax-table) (setq local-abbrev-table nov-mode-abbrev-table) (add-hook (quote kill-buffer-hook) (quote nov-clean-up) nil t) (add-hook (quote kill-emacs-hook) (quote nov-clean-up-all)) (add-hook (quote change-major-mode-hook) (quote nov-clean-up) nil t) (if (not buffer-file-name) (progn (error "EPUB must be associated with file"))) (setq nov-temp-dir (make-temp-file "nov-" t ".epub")) (let ((exit-code (nov-unzip-epub nov-temp-dir buffer-file-name))) (if (not (integerp exit-code)) (progn (nov-clean-up) (error "EPUB extraction aborted by signal %s" exit-code))) (if (not (= 0 exit-code)) (progn (nov-clean-up) (error "EPUB extraction failed with exit code %d" exit-code)))) (if (not (nov-epub-valid-p nov-temp-dir)) (progn (nov-clean-up) (error "Invalid EPUB file"))) (let* ((content (nov-slurp (nov-container-filename nov-temp-dir) t)) (content-file (nov-make-path nov-temp-dir (nov-container-content-filename content))) (work-dir (file-name-directory content-file)) (content (nov-slurp content-file t))) (setq nov-content-file content-file) (setq nov-epub-version (nov-content-version content)) (setq nov-metadata (nov-content-metadata content)) (setq nov-documents (apply (quote vector) (nov-content-files work-dir content))) (setq nov-documents-index 0)) (setq buffer-undo-list t) (set-visited-file-name nil t) (let ((place (nov-saved-place (cdr (assq ... nov-metadata))))) (if place (let ((index (cdr ...)) (point (cdr ...))) (setq nov-documents-index index) (nov-render-document) (goto-char point)) (nov-render-document)))))
  nov-mode()
  funcall-interactively(nov-mode)
  call-interactively(nov-mode record nil)
  command-execute(nov-mode record)
  execute-extended-command(nil "nov-mode" nil)
  funcall-interactively(execute-extended-command nil "nov-mode" nil)
  call-interactively(execute-extended-command nil nil)
  command-execute(execute-extended-command)

Emacs 25.3.1 with Borg and Nov, tested with version 0.2.2 and git head.

Thanks !


About linking the epub: the book is now released under the CC BY-SA license, so I think I can legally share it. Please tell me if I should put the link down.

Image rendering

My emacs is not compiled for image support. When I hit a png file, it obviously doesn't render, but it doesn't load the rest of the chapter. This is the error I receive:
Invalid image type ‘png’

Is there a way to include an option to not render images and just put a place holder in its place instead?

Question on Adobe DRM

Thank you for this excellent mode for Emacs. I've been using it to read EPUBs from Project Gutenberg, but now I'm ready to buy a few EPUBs that have this Adobe DRM. Can such books be opened/read in nov.el?
Thank you very much for your time!

Confusing little square boxes seen in epub

Hi,

Thank you very much for working on this package! I can now finally start reading technical ebooks in emacs too!

I tried this package on the book I am reading right now (Nim in Action). Overall, nov.el does an awesome job. The only thing that stands out is the presence of these big gray boxes through the whole book. I do not understand what element in the .epub renders to those boxes. But this screenshot might give you a better idea (the yellow highlighting is done by me to match the lines I could correlate between the raw and rendered epub):

image

Is it able to render the content nicely in Emacs?

I like the navigate the epub file with shortcuts a lot, but this is package will be better if it can render the content nicely in Emacs.

  1. margins
  2. wrap long lines
  3. change font
  4. multiple color and style of fonts (defined in epub files)

error "Unique identifier not found by its name: PrimaryID"

  • GNU Emcas 27.0.50
  • macOS Catalina
Debugger entered--Lisp error: (error "Unique identifier not found by its name: PrimaryID")
  signal(error ("Unique identifier not found by its name: PrimaryID"))
  error("Unique identifier not found by its name: %s" "PrimaryID")
  nov-content-unique-identifier((package ((version . "2.0") (unique-identifier . "PrimaryID") (mlns . "http://www.idpf.org/2007/opf")) (metadata nil (title nil "黄金瞳") (identifier (...)) (language nil "zh") (creator nil "打眼") (publisher nil "www.shushu8.com") (description nil) (coverage nil) (source nil "http://www.shushu8.com") (date nil "2019-09-05") (rights nil "欢迎访问http://www.shushu8.com下载海量电子...") (subject nil "玄幻魔法") (contributor nil) (type nil "epub") (format nil) (relation nil) (builder nil "phpepub") (builder_version nil "1.0") (meta (... ...))) (manifest nil (comment nil " Content Documents ") (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) ...) (spine ((toc . "ncx")) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) ...) (guide nil (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) ...)))
  nov-content-metadata((package ((version . "2.0") (unique-identifier . "PrimaryID") (mlns . "http://www.idpf.org/2007/opf")) (metadata nil (title nil "黄金瞳") (identifier (...)) (language nil "zh") (creator nil "打眼") (publisher nil "www.shushu8.com") (description nil) (coverage nil) (source nil "http://www.shushu8.com") (date nil "2019-09-05") (rights nil "欢迎访问http://www.shushu8.com下载海量电子...") (subject nil "玄幻魔法") (contributor nil) (type nil "epub") (format nil) (relation nil) (builder nil "phpepub") (builder_version nil "1.0") (meta (... ...))) (manifest nil (comment nil " Content Documents ") (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) (item (... ... ...)) ...) (spine ((toc . "ncx")) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) (itemref (... ...)) ...) (guide nil (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) (reference (... ... ...)) ...)))
  nov-mode()
  set-auto-mode-0(nov-mode nil)
  set-auto-mode()
  normal-mode(t)
  after-find-file(nil t)
  find-file-noselect-1(#<buffer 黄金瞳_打眼.epub> "~/Documents/Books/Novel/黄金瞳_打眼.epub" nil nil "~/Documents/Books/Novel/黄金瞳_打眼.epub" (8644715430 16777220))
  find-file-noselect("/Users/vincent/Documents/Books/Novel/黄金瞳_打眼.epub" nil nil nil)
  find-file("/Users/vincent/Documents/Books/Novel/黄金瞳_打眼.epub")

Different Font

Is there a way to change the font for nov.el?
I changed the default font for testing but that didn't change the font in nov.el

Feature Request: Configure Progress File Location

Hi, thanks for this library, I'm enjoying using it so far.

Is it possible to configure where the nov-places file is created and accessed? It seems like by default it's created in my .emacs.d directory and I'm not sure if this is intended or due to configuration I have elsewhere. I have this directory under version control, so I was hoping to save nov-places elsewhere if possible.

Thanks!

Inline color styles are not honored

The book https://www.jyotirmoy.net/posts/2018-12-01-rust-book.html is a good example of a typical programming epub. It contains code snippets that have been syntax highlightened and annotated with tags like <span class="pp">println!</span>(<span class="st">&quot;Hello, world!&quot;</span>);. The xhtml also contains an inline style sheet which defines the attributes of these classes:

code span.pp { color: #bc7a00; } /* Preprocessor */
code span.sc { color: #4070a0; } /* SpecialChar */
code span.ss { color: #bb6688; } /* SpecialString */
code span.st { color: #4070a0; } /* String */

But these styles are not honored in the display and the code is displayed in black only.

See: ch002.xhtml of the reference epub.

Can't read some pages due to url encoded references

I have this epub that throws an error about not finding the xhtml file when reading some pages.
The xhtml file does exist, but it contains spaces, so it's url encoded on the content.opf

Here is the traceback.

Debugger entered--Lisp error: (file-missing "Opening input file" "No such file or directory" "/tmp/nov-exk8tU.epub/OEBPS/2.%20The%20Political%20Arithmetic%20of%20Piracy.xhtml")
  insert-file-contents("/tmp/nov-exk8tU.epub/OEBPS/2.%20The%20Political%20Arithmetic%20of%20Piracy.xhtml")
  nov-slurp("/tmp/nov-exk8tU.epub/OEBPS/2.%20The%20Political%20Arithmetic%20of%20Piracy.xhtml")
  nov-render-document()
  nov-next-document()
  funcall-interactively(nov-next-document)
  call-interactively(nov-next-document nil nil)
  command-execute(nov-next-document)

While epubcheck does throw a few warnings, and recommends avoiding spaces as they need to be url encoded, as far as I have researched, it doesn't seem to be against the standard.

It doesn't seem to be a bad idea to url decode this references.

Can't open some ePub files

This may very well be an issue with the ePub files, but since Calibre can open them, I thought I would log it...

I try to open the ePub from a dired listing and instead of interpreting the file correctly it just shows the data (all the characters of a binary, compressed file) with the error:

File mode specification error: (error Unique identifier not found by its name: uuid_id)

I'm not sure how to debug further, but if I can get you more data, let me know.

Thanks,
Bruce

Font Size and Text Width

I have been playing with nov-text-width and the command text-scale-adjust to get the text at a size suitable to my small screen.
However, I found an issue I have no idea how to fix, but I know how to replicate.

Issue:
If I set (setq nov-text-width 45) and open a book, then I see the following:
Screen Shot 2019-07-18 at 2 55 26 PM

If I scroll to the next page with SPC, I get the following view:
Screen Shot 2019-07-18 at 2 57 13 PM

If I scroll back to the previous page with S-SPC, then I get the following view:
Screen Shot 2019-07-18 at 2 58 00 PM

It seems that when I first open the book, the column width is not being completely respected.
After moving to the next page, the text gets rearranged to fit a smaller width.
Now, when I move back to the original page, the text that was previously displayed over a larger width, is now rearranged to occupy a smaller width.

EPUB buffer is not associated its original file or at least it does not show its file path in *Buffer list*

I'm using pesrp-mode in spacemacs to save and restore the last buffers and the layout of workspaces. When persp has tried to restore EPUB buffer, it has spitted the message "EPUB must be associated with file" . I'm not sure that persp-mode really requires buffer-associated file path. But in case of PDFView buffer it is associated with its file path and show it in *Buffer List*. So I guess that if nov make EPUB buffer associated with its file path then persp-mode can restore it. Could I expect some improvement?

readme example triggering arg-out-of-range

I was trying to achieve the same rendering as the screenshot in the readme by following the instructions but I keep getting this error: File mode specification error: (args-out-of-range nil 256204778801521549).
I opened this issue as asked at #51.

Following is the minimal configuration triggering the issue, my-nov-post-html-render-hook is from README.org file:

(use-package! nov
  :mode ("\\.epub\\'" . nov-mode)
  :requires (justify-kp)
  :hook ((nov-mode . my-nov-post-html-render-hook))
  :config
  (setq nov-text-width most-positive-fixnum))

On NixOS 19.03 with emacs 26.1.

Wrong type argument: listp, "images/00004.jpg"

First of all, I thank you for putting efforts in making this package available, love it.

But I have an issue while opening some epub files with minibuffer error message described in the title. Probably involving epub with image in it. How can K solve this?

Unable to run nov-mode on Windows

Hey, disclaimer: I'm still relatively new to Emacs.

When I open an Epub on Windows, Emacs opens it using Zip-Archive mode and displays its content (which is normal afaik).

image

However, when I start nov-mode, encoded characters are displayed and I got an error of "Wrong type argument: stringp, nil" in the mini-buffer.

image

What should I do? Where should I look?
Thanks for the help.

most-positive-fixnum is too big

Debugger entered--Lisp error: (args-out-of-range nil 2305843009213693951)
  vertical-motion((2305843009213693951 . 0))
  shr-vertical-motion(2305843009213693951)
  shr-fill-line()
  shr-fill-lines(1 5339)
  shr-insert-document((html ((xmlns . "http://www.w3.org/1999/xhtml")) (head nil (title nil "Programming Elixir ≥ 1.6") (link ((rel . "stylesheet") (type . "text/css") (href . "css/bookshelf.css"))) (link ((rel . "stylesheet") (type . "text/css") (href . "css/book_local.css")))) (body nil "\n" (h2 ((id . "d25e218")) "Programming Should Be About Transforming Data") "\n" (p ((id . "d25e221")) "\nIf you come from an object-oriented world, then you are\nused to thinking in terms of classes and their instances. A class\ndefines behavior, and objects hold state. Developers spend time coming\nup with intricate hierarchies of classes that try to model their\nproblem, much as Victorian scientists created taxonomies of\nbutterflies.") "\n" (p ((id . "d25e225")) "\nWhen we code with objects, we’re thinking about state. Much of our\ntime is spent calling methods in objects and passing them other\nobjects. Based on these calls, objects update their own state, and\npossibly the state of other objects. In this world, the class is\nking—it defines what each instance can do, and it implicitly controls\nthe state of the data its instances hold. Our goal is data-hiding.") "\n" (p ((id . "d25e236")) "But that’s not the real world. In the real world, we don’t want to\nmodel abstract hierarchies (because in reality there aren’t that\nmany true hierarchies). We want to get things done,\nnot maintain state.") "\n" (p ((id . "d25e238")) "Right now, for instance, I’m taking empty computer files and transforming them into files\ncontaining text. Soon I’ll transform those files into a\nformat you can read. A web server somewhere will transform your\nrequest to download the book into an HTTP response containing the\ncontent.") "\n" (p ((id . "d25e240")) "I don’t want to hide data. I want to transform it.") (h3 nil "Combine Transformations with Pipelines") "\n" (p ((id . "d25e245")) "\n\n\n\nUnix users are accustomed to the philosophy of small, focused command-line\ntools that can be combined in arbitrary ways. Each tool takes an\ninput, transforms it, and writes the result in a format the next\ntool (or a human) can use.") "\n" (p ((id . "d25e273")) "This philosophy is incredibly flexible and leads to fantastic\nreuse. The Unix utilities can be combined in ways undreamed of by\ntheir authors. And each one multiplies the potential of the others.") "\n" (p ((id . "d25e275")) "It’s also highly reliable—each small program does one thing well,\nwhich makes it easier to test.") "\n" (p ((id . "d25e277")) "\nThere’s another benefit. A command pipeline can operate in\nparallel. If I write") (table ((shr-fixed-table . t) (shr-suggested-widths ((2 . 2) (51 . 51)))) (tr nil (td ((class . "codeinfo") (shr-td-cache-natural . 2) (shr-td-cache-1152921504606846976-nil 2 2 1 ... 1 nil nil)) "​" (span (...) " ")) (td ((class . "codeline") (shr-td-cache-natural . 51) (shr-td-cache-1152921504606846976-nil 51 51 1 ... 1 nil nil)) "​" (span (...) "$ ") "​​" (strong (...) "grep") "​​" (strong (...) " ") "​​" (strong (...) "Elixir") "​​" (strong (...) " ") "​​" (strong (...) "*.pml") "​​" (strong (...) " ") "​​" (strong (...) "|") "​​" (strong (...) " ") "​​" (strong (...) "wc") "​​" (strong (...) " ") "​​" (strong (...) "-l") "​"))) (p ((id . "d25e309")) "the word-count program, " (span ((class . "cf ic")) "wc") ", runs at the same time as the " (span ((class . "cf ic")) "grep") "\ncommand. Because " (span ((class . "cf ic")) "wc") " consumes " (span ((class . "cf ic")) "grep") "’s output as it is produced, the\nanswer is ready with virtually no delay once " (span ((class . "cf ic")) "grep") " finishes.") "\n" (p ((id . "d25e326")) "\n\n\nJust to give you a taste of this, here’s an Elixir\nfunction called " (span ((class . "cf ic")) "pmap") ". It takes a collection and a function, and\nreturns the list that results from applying that function to each\nelement of the collection. But…it runs a separate process to do the\nconversion of each element. Don’t worry about the details for now.") (div ((class . "livecodelozenge")) (a ((href . "http://media.pragprog.com/titles/elixir16/code/spawn/pmap1.exs")) "spawn/pmap1.exs")) (table ((shr-fixed-table . t) (shr-suggested-widths ((2 . 2) (25 . 25)) ((2 . 2) (33 . 33)) ((2 . 2) (10 . 10)) ((2 . 2) (51 . 51)) ((2 . 2) (26 . 26)) ((2 . 2) (5 . 5)) ((2 . 2) (5 . 5)))) (tr nil (td ((class . "codeinfo") (shr-td-cache-natural . 2) (shr-td-cache-1152921504606846976-nil 2 2 1 ... 1 nil nil)) "​" (span (...) " ")) (td ((class . "codeline") (shr-td-cache-natural . 25) (shr-td-cache-1152921504606846976-nil 25 25 1 ... 1 nil nil)) "​" (strong (...) "defmodule") "​ Parallel ​" (strong (...) "do") "​")) (tr nil (td ((class . "codeinfo") (shr-td-cache-natural . 2) (shr-td-cache-1152921504606846976-nil 2 2 1 ... 1 nil nil)) "​" (span (...) " ")) (td ((class . "codeline") (shr-td-cache-natural . 33) (shr-td-cache-1152921504606846976-nil 33 33 1 ... 1 nil nil)) "  ​" (strong (...) "def") "​ pmap(collection, func) ​" (strong (...) "do") "​")) (tr nil (td ((class . "codeinfo") (shr-td-cache-natural . 2) (shr-td-cache-1152921504606846976-nil 2 2 1 ... 1 nil nil)) "​" (span (...) " ")) (td ((class . "codeline") (shr-td-cache-natural . 10) (shr-td-cache-1152921504606846976-nil 10 10 1 ... 1 nil nil)) "    collection")) (tr nil (td ((class . "codeinfo") (shr-td-cache-natural . 2) (shr-td-cache-1152921504606846976-nil 2 2 1 ... 1 nil nil)) "​" (span (...) " ")) (td ((class . "codeline") (shr-td-cache-natural . 51) (shr-td-cache-1152921504606846976-nil 51 51 1 ... 1 nil nil)) "    |> Enum.map(&(Task.async(​" (strong (...) "fn") "​ -> func.(&1) ​" (strong (...) "end") "​)))")) (tr nil (td ((class . "codeinfo") (shr-td-cache-natural . 2) (shr-td-cache-1152921504606846976-nil 2 2 1 ... 1 nil nil)) "​" (span (...) " ")) (td ((class . "codeline") (shr-td-cache-natural . 26) (shr-td-cache-1152921504606846976-nil 26 26 1 ... 1 nil nil)) "    |> Enum.map(&Task.await/1)")) (tr nil (td ((class . "codeinfo") (shr-td-cache-natural . 2) (shr-td-cache-1152921504606846976-nil 2 2 1 ... 1 nil nil)) "​" (span (...) " ")) (td ((class . "codeline") (shr-td-cache-natural . 5) (shr-td-cache-1152921504606846976-nil 5 5 1 ... 1 nil nil)) "  ​" (strong (...) "end") "​")) (tr nil (td ((class . "codeinfo") (shr-td-cache-natural . 2) (shr-td-cache-1152921504606846976-nil 2 2 1 ... 1 nil nil)) "​" (span (...) " ")) (td ((class . "codeline") (shr-td-cache-natural . 5) (shr-td-cache-1152921504606846976-nil 5 5 1 ... 1 nil nil)) "​" (strong (...) "end") "​"))) (p ((id . "d25e377")) "We could run this function to get the squares of the numbers from 1 to\n1,000.") (table ((shr-fixed-table . t) (shr-suggested-widths ((2 . 2) (44 . 44)))) (tr nil (td ((class . "codeinfo") (shr-td-cache-natural . 2) (shr-td-cache-1152921504606846976-nil 2 2 1 ... 1 nil nil)) "​" (span (...) " ")) (td ((class . "codeline") (shr-td-cache-natural . 44) (shr-td-cache-1152921504606846976-nil 44 44 1 ... 1 nil nil)) "result = Parallel.pmap 1..1000, &(&1 ​" (strong (...) "*") "​ &1)"))) (p ((id . "d25e386")) "And, yes, I just kicked off 1,000 background processes, and I used all\nthe cores and processors on my machine.") "\n" (p ((id . "d25e388")) "The code may not make much sense, but by about halfway through the\nbook, you’ll be writing this kind of thing for yourself.") (h3 nil "Functions Are Data Transformers") "\n" (p ((id . "d25e393")) "\nElixir lets us solve the problem in the same way the Unix shell\ndoes. Rather than have command-line utilities, we have functions. And\nwe can string them together as we please. The smaller—more\nfocused—those functions, the more flexibility we have when combining\nthem.") "\n" (p ((id . "d25e399")) "\n\n\n\n\n\nIf we want, we can make these functions run in parallel—Elixir has a\nsimple but powerful mechanism for passing messages between them. And\nthese are not your father’s boring old processes or threads—we’re\ntalking about the potential to run millions of them on a single\nmachine and have hundreds of these machines interoperating. Bruce\nTate commented on this paragraph with this thought: “Most programmers treat threads\nand processes as a necessary evil; Elixir developers feel they are an\nimportant simplification.” As we get deeper into the book, you’ll\nstart to see what he means.") "\n" (p ((id . "d25e422")) "This idea of transformation lies at the heart of functional\nprogramming: a function transforms its inputs into its output. The\ntrigonometric function " (span ((class . "emph")) "sin") " is an example—give it\n" (span ((style . "font-family:Quivira;")) "π") "/4, and you’ll get\nback 0.7071. An HTML templating system is a function; it takes a\ntemplate containing placeholders and a list of named\nvalues, and produces a completed HTML document.") "\n" (p ((id . "d25e433")) "But this power comes at a price. You’re going to have to unlearn a\nwhole lot of what you " (span ((class . "emph")) "know") " about programming. Many of your instincts\nwill be wrong. And this will be frustrating, because you’re going to\nfeel like a total n00b.") "\n" (p ((id . "d25e438")) "Personally, I feel that’s part of the fun.\nYou didn’t learn, say, object-oriented programming overnight. You are\nunlikely to become a functional programming expert by breakfast,\neither.") "\n" (p ((id . "d25e440")) "But at some point things will click. You’ll start thinking about\nproblems in a different way, and you’ll find yourself writing code\nthat does amazing things with very little effort on your part. You’ll\nfind yourself writing small chunks of code that can be used over and\nover, often in unexpected ways (just as " (span ((class . "cf ic")) "wc") " and " (span ((class . "cf ic")) "grep") " can be).") "\n" (p ((id . "d25e448")) "Your\nview of the world may even change a little as you stop thinking in terms of responsibilities and start thinking in terms of\ngetting things done.\nAnd just about everyone can agree that will be fun.\n\n\n\n") "\n")))
  shr-render-region(1 8047)
  nov-render-html()
  nov-render-document()
  nov-mode()
  set-auto-mode-0(nov-mode nil)
  set-auto-mode()
  normal-mode(t)
  after-find-file(nil t)
  find-file-noselect-1(#<buffer ProgrammingElixir.epub • book> "~/Documents/book/ProgrammingElixir.epub" nil nil "~/Documents/book/ProgrammingElixir.epub" (4771104 16777222))
  find-file-noselect("/Users/tboevil/Documents/book/ProgrammingElixir.epub")
  server-visit-files((("/Users/tboevil/Documents/book/ProgrammingElixir.epub")) #<process server <24>> nil)
  server-execute(#<process server <24>> (("/Users/tboevil/Documents/book/ProgrammingElixir.epub")) nil nil t #<frame F19 0x106672ed0> "/dev/ttys002")
  #f(compiled-function () #<bytecode 0x42747629>)()
  server-execute-continuation(#<process server <24>>)
  server-process-filter(#<process server <24>> "-env ALL_PROXY=http://127.0.0.1:6152 -env Apple_PubSub_Socket_Render=/private/tmp/com.apple.launchd.11PLeZPvB7/Render -env COLORFGBG=12;8 -env COLORTERM=truecolor -env COMMAND_MODE=unix2003 -env EDITOR=emacsclient&_-t -env FTP_PROXY=http://127.0.0.1:6152 -env GEM_HOME=/Users/tboevil/.rvm/gems/ruby-2.5.5 -env GEM_PATH=/Users/tboevil/.rvm/gems/ruby-2.5.5:/Users/tboevil/.rvm/gems/ruby-2.5.5@global -env HOME=/Users/tboevil -env HTTPS_PROXY=http://127.0.0.1:6152 -env HTTP_PROXY=http://127.0.0.1:6152 -env ITERM_PROFILE=Hotkey&_Window -env ITERM_SESSION_ID=w0t3p1:DA0EFFBA-BFBF-4294-BD96-6FB9A517D499 -env LC_CTYPE=UTF-8 -env LOGNAME=tboevil -env NVM_BIN=/Users/tboevil/.nvm/versions/node/v11.10.1/bin -env NVM_CD_FLAGS= -env NVM_DIR=/Users/tboevil/.nvm -env OMF_CONFIG=/Users/tboevil/.config/omf -env OMF_PATH=/Users/tboevil/.local/share/omf -env PASSWORD_STORE_CHARACTER_SET=abcdefghijklmnopqrstuvwxyz1234567890,.\\+\\-()@:;* -env PATH=/Users/tboevil/.rvm/gems/ruby-2.5.5/bin:/Users/tboevil/.rvm/gems/ruby-2.5.5@global/bin:/Users/tboevil/.rvm/rubies/ruby-2.5.5/bin:/Users/tboevil/.nvm/versions/node/v11.10.1/bin:/Users/tboevil/.my_script/bin/:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Users/tboevil/.rvm/bin -env PWD=/Users/tboevil/.emacs.d/package -env RUBY_VERSION=ruby-2.5.5 -env SECURITYSESSIONID=186a8 -env SHELL=/usr/local/bin/fish -env SHLVL=1 -env SSH_AUTH_SOCK=/private/tmp/com.apple.launchd.LFyMXlg29Q/Listeners -env TERM=xterm-256color -env TERM_PROGRAM=iTerm.app -env TERM_PROGRAM_VERSION=3.2.8 -env TERM_SESSION_ID=w0t3p1:DA0EFFBA-BFBF-4294-BD96-6FB9A517D499 -env TMPDIR=/var/folders/0r/r_0tt7wj1p1b9ysmy19sklph0000gn/T/ -env USER=tboevil -env XPC_FLAGS=0x0 -env XPC_SERVICE_NAME=0 -env __CF_USER_TEXT_ENCODING=0x0:0:0 -env all_proxy=http://127.0.0.1:6152 -env ftp_proxy=http://127.0.0.1:6152 -env http_proxy=http://127.0.0.1:6152 -env https_proxy=http://127.0.0.1:6152 -env rvm_bin_path=/Users/tboevil/.rvm/bin -env rvm_path=/Users/tboevil/.rvm -env rvm_prefix=/Users/tboevil -env rvm_version=1.29.7&_latest -dir /Users/tboevil/.emacs.d/package/ -tty /dev/ttys002 xterm-256color -file /Users/tboevil/Documents/book/ProgrammingElixir.epub \n")

I think should remove it from document

should support .dir-locals.el

It would be helpful if nov.el would evaluate a .dir-locals.el file. I use this e.g. to set up dictionary lookup for my ebooks.

Thanks for nov.el it's really useful.

dired-current-directory: No subdir-alist in <name of epub file>

nov works well for me except for one little glitch. When I have nov set to be the autoloaded mode for epubs, it initially gives the error: dired-current-directory: No subdir-alist in
when I try to open an epub.

nov does find my unzip and my emacs is GNU Emacs 25.2.1 (x86_64-apple-darwin13.4.0, Carbon Version 157 AppKit 1265.21) of 2017-05-22
which I assume has libxml2 compiled in.

Despite the aforementioned error, the file does open in a buffer, but not the current buffer. I can then select the buffer where it is open and use nov fine. Having the error at the time of opening the file makes things like org-noter fail, which is a bummer. Perhaps it has to do with my setup, not sure. Any ideas?

Add nov-mode to auto-mode-alist With an Autoload Cookie

This is something that you may be aware of, but have decided not to include. If so, I'd love to know your reasoning.

It would be a nice little touch to have something like this in nov-mode:

;;;###autoload
(add-to-list 'auto-mode-alist (cons "\\.epub\\'" 'nov-mode))

This should remove the need for users to register the epub file format manually in their init file.

Thanks!

Add Emacspeak support

Emacspeak, found at
http://www.github.com/tvraman/emacspeak/
is an auditory interface to Emacs. As a blind user of Emacs, I use it as a sort of operating system for all my textual needs, including reading books. Nov-mode works well now, but there could be some improvements.
Usually, in modes like Info, pressing space not only scrolls, but speaks the scrolled text. In nov-mode, C-v speaks and scrolls, but space only seems to scroll a few lines down.
In info-mode, pressing N or P speaks the whole entry. Perhaps this would not be desirable in nov-mode, but at least speaking the chapter name would be fine.
Whenever an image is encountered, pressing C-n does not go passed the image, but I can get around that by pressing C-f a few times, then C-n to continue down through lines.
Everything else works fine, and I love using Nov-mode, as it's the only accessible Epub reader I have on the Mac.

Enhancement: Being able to extract images and copy them to other files

I sometimes copy text from EPUBs and keep them in some org files. I was hoping for a feature to be able to also extract images and copy them there as well.

I am not sure if that is even possible to achieve, just throwing it out there in case others are interested in this feature and willing to weigh in.

Jump back to the previous location?

Sometimes I jump to:

  • notes in Bibliography
  • a new Chapter

Demo

but have no idea how to go back.

My current solution is pressing t and finding the previous chapter, location manually. But it's a very bad experience.

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.