想用Emacs看一本epub格式的书.
虽然Win下面有许多程序可以看, 但是考虑到可能要翻译字词或者做做笔记什么的, 于是就想和 Emacs 结合一下, 但是直接打开似乎是无法做到, 默认的功能也没有 epub 相关的mode 所以请教一下论坛, 有没有类似的解决方案呢? 谢谢~
想用Emacs看一本epub格式的书.
虽然Win下面有许多程序可以看, 但是考虑到可能要翻译字词或者做做笔记什么的, 于是就想和 Emacs 结合一下, 但是直接打开似乎是无法做到, 默认的功能也没有 epub 相关的mode 所以请教一下论坛, 有没有类似的解决方案呢? 谢谢~
嗯嗯, 在 package list 里面找到了, 不过打开文件的时候error了:joy:
path 设置了 unzip.
不过打开报了一个错
nov-mode: EPUB extraction failed with exit code 9 Mark set
内容也是一些乱码, 看起来好像是编码的问题.
还是谢谢回答
真是非常抱歉,一年多了还来挖坟
今天正好试用了这个包,也遇到了和楼主一样的问题。我发现这是 unzip
解压失败导致的,只发生在 「Windows + 中文文件名」这种情况下。以下设置可以解决这个问题:
(with-eval-after-load "nov"
(when (string-equal system-type "windows-nt")
(setq process-coding-system-alist
(cons `(,nov-unzip-program . (gbk . gbk))
process-coding-system-alist))))
具体的原理我还没弄得很清楚,但基本可以确定是「coding system for subprocess I/O」的问题。
因为windows的中文是用gbk编码的。emacs里默认utf8
呃,用第二个在Windows10上打开好几本书都只有一片空白,不知道原因…
在win10下用这个能看一些书,但Springer出的一些材料类的epub用它打开都只能看目录,在章节上一回车,Emacs就死在那儿了…
成功解决问题…感谢感谢…
有时候打开 epub 无法处理 unicode 字符,可以用下面这个 workaround
;; FIXME: errors while opening `nov' files with Unicode characters
(with-no-warnings
(defun my-nov-content-unique-identifier (content)
"Return the the unique identifier for CONTENT."
(when-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)))))
(intern id)))
(advice-add #'nov-content-unique-identifier :override #'my-nov-content-unique-identifier))
这段代码加上后,各种问题都解决了… 包括之前从目录进章节导致Emacs停止响应的那本书, 也能打开了… 感觉很神奇的样子… 谢谢。
可惜作者不愿意改,说书的格式不正确就应该报错。幸亏 Emacs,我可以自己改了。
有些中文书打开是乱码,有些则正常。
你需要检查下电子书的格式和编码是否正确了。
谢谢,最近正好遇到了这两个问题。不过问题好像还没有完全解决,又遇到了一个 “EPUB 3 ID not found"的问题,查了一下nov.el源码,好像是在nov–content-epub3-files这个函数里,esxml-query找不到 id,不知可有办法?
我没有遇到这个问题,你可以按照相同思路修改一下,分享到这里
找到问题的原因了,部分版本号显示为EPUB3格式的电子书实际上格式是EPUB2,这样就导致按照EPUB3方式解析出错。实现思路是在按照EPUB3解析失败后再退回到EPUB2解析。不过我对elisp是个新手,对于nov–content-epub3-files中的error不知道怎么处理,也没有找到相关资料,麻烦帮忙看看。
(defun nov--content-epub2-files (content manifest files)
(let* ((node (esxml-query "package>spine[toc]" content))
(id (esxml-node-attribute 'toc node)))
(when (not id)
(error "EPUB 2 NCX ID not found"))
(setq nov-toc-id (intern id))
(let ((toc-file (assq nov-toc-id manifest)))
(when (not toc-file)
(error "EPUB 2 NCX file not found"))
(cons toc-file files))))
(defun nov--content-epub3-files (content manifest files)
(let* ((node (esxml-query "package>manifest>item[properties~=nav]" content))
(id (esxml-node-attribute 'id node)))
(when (not id)
(error "EPUB 3 <nav> ID not found"))
(setq nov-toc-id (intern id))
(let ((toc-file (assq nov-toc-id manifest)))
(when (not toc-file)
(error "EPUB 3 <nav> file not found"))
(setq files (--remove (eq (car it) nov-toc-id) files))
(cons toc-file files))))
整体思路没错,不过跟nov.el本身的设计思路相悖。nov作者的本意是如果格式错误就直接报错退出。如果要修改就不能用error,因为error会直接退出处理。nov--content-epub2-files
, nov--content-epub3-files
, nov-centent-files
等多个函数都需要修改,改动会比较大。
发现错误后,用EpubCheck 检查修复下文件可能才是解决之道。
如果非要改,可以试试下面这个workaround(刚随手写的,没有测试过):
(defun nov--content-epub2-files (content manifest files)
(let* ((node (esxml-query "package>spine[toc]" content))
(id (esxml-node-attribute 'toc node)))
(when (not id)
(throw 'error "EPUB 2 NCX ID not found"))
(setq nov-toc-id (intern id))
(let ((toc-file (assq nov-toc-id manifest)))
(when (not toc-file)
(throw 'error "EPUB 2 NCX file not found"))
(cons toc-file files))))
(defun nov--content-epub3-files (content manifest files)
(let* ((node (esxml-query "package>manifest>item[properties~=nav]" content))
(id (esxml-node-attribute 'id node)))
(when (not id)
(throw 'error "EPUB 3 <nav> ID not found"))
(setq nov-toc-id (intern id))
(let ((toc-file (assq nov-toc-id manifest)))
(when (not toc-file)
(throw 'error "EPUB 3 <nav> file not found"))
(setq files (--remove (eq (car it) nov-toc-id) files))
(cons toc-file files))))
(defun nov-content-files (directory content)
"Create correctly ordered file alist for CONTENT in DIRECTORY.
Each alist item consists of the identifier and full path."
(let* ((manifest (nov-content-manifest directory content))
(spine (nov-content-spine content))
(files (mapcar (lambda (item) (assq item manifest)) spine)))
(catch 'error (nov--content-epub3-files content manifest files))
(catch 'error (nov--content-epub2-files content manifest files))))