1 ;;; org-kindle.el --- Send org link file to ebook reader.
3 ;; Authors: stardiviner <numbchild@gmail.com>
4 ;; Package-Requires: ((emacs "25") (cl-lib "0.5") (seq "2.20"))
5 ;; Package-Version: 0.1
6 ;; Keywords: org link ebook kindle epub azw3 mobi
7 ;; homepage: https://repo.or.cz/org-kindle.git
9 ;; org-kindle is free software; you can redistribute it and/or modify it
10 ;; under the terms of the GNU General Public License as published by
11 ;; the Free Software Foundation; either version 3, or (at your option)
14 ;; org-kindle is distributed in the hope that it will be useful, but WITHOUT
15 ;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16 ;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
17 ;; License for more details.
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
24 ;; This is package makes an Emacs bridge between Kindle (other ereaders
25 ;; supports could work in theoretically) and Org Mode.
26 ;; In theatrically, this package should work for non-kindle ereaders too. User can
27 ;; set device path in variables. But becaused not tested, so I can't guarantee that
28 ;; package will work correctly. But PR welcome to improve it. I appreciate it.
30 ;; This packages use a command `ebook-convert' which comes from
31 ;; [[https://calibre-ebook.com/][Calibre]]. So if you want to use auto convert
32 ;; functionality, you need to install it manuall.
34 ;; - It support send Org Mode file: link file to Kindle or other ereaders like Nook.
38 ;; - Support sync Kindle notes with Org Mode notes file.
46 (require 'cl-lib
) ; for `cl-case'
47 (require 'seq
) ; for `seq-filter'
49 (require 'org-element
)
50 (require 'dash
) ; for `->>'
52 (defgroup org-kindle nil
53 "Send org-mode ebook file: link to external devices with corresponding formats.."
57 (defvar org-kindle-supported-devices-alist
58 '(:kindle
(:name
"Kindle" :device-name
"Amazon Kindle"
59 :documents-path
"/Kindle/documents/")
60 :nook
(:name
"Nook" :device-name
"Nook"
61 :documents-path
"" ; FIXME:
63 "Alist of package supported devices.")
65 (defvar org-kindle-target-format nil
)
67 (defcustom org-kindle-default-format
".epub"
68 "The default target device format used to send."
73 (defun org-kindle--read-device-info ()
74 "Match name in shell command lsusb listed out devices."
77 (if (file-exists-p "/Volumes/kindle")
84 (string-match (rx "Amazon Kindle") usb
))
85 (split-string (shell-command-to-string "lsusb") "\n")) "kindle")
88 (string-match (rx "Nook") usb
))
89 (split-string (shell-command-to-string "lsusb") "\n")) "nook")
92 (warn "unknown device, can't detect device correctly,\n
93 please report to https://repo.or.cz/org-kindle.git")
97 (defun org-kindle--detect-format ()
98 "Detect plugged in device's ebook format."
99 (cl-case (intern (org-kindle--read-device-info))
102 (t org-kindle-default-format
)))
105 (defun org-kindle--mount-path ()
106 "Get Linux general mount path."
109 (directory-file-name (concat "/run/media/" (getenv "USER"))))
111 (directory-file-name "/Volumes/"))
116 (defun org-kindle--detect-directory ()
117 "Detect plugged in device directory of saving ebook."
118 (cl-case (intern (org-kindle--read-device-info))
121 (concat (org-kindle--mount-path)
122 (plist-get (plist-get org-kindle-supported-devices-alist
:kindle
)
125 (read-directory-name "Send to device directory: "))))
127 (defun org-kindle--file-name-escape-special-chars (filename)
128 "Escape special characters like : in filename which invalid in copying filename."
130 (replace-regexp-in-string ":" "\\\\:")
131 (replace-regexp-in-string " " "\\\\ ")))
133 (defun org-kindle--file-name-strim-special-chars (filename)
134 "strim some special characters in filename which does not
135 supported by Kindle filesystem."
137 (replace-regexp-in-string ":" "-")))
140 (defun org-kindle-send-to-device ()
141 "Send `org-mode' ebook file: link to external devices with corresponding formats."
143 ;; get the file path under org-mode link.
144 (when (string= (org-element-property :type
(org-element-context)) "file")
145 (let* ((source-file (expand-file-name (org-link-unescape (org-element-property :path
(org-element-context)))))
146 (target-file-name (org-kindle--file-name-strim-special-chars
147 (file-name-nondirectory
148 (concat (file-name-sans-extension source-file
)
149 (org-kindle--detect-format)))))
150 (default-directory (temporary-file-directory))
151 (convert-temp-file (concat (temporary-file-directory) target-file-name
))
152 (device-directory (org-kindle--detect-directory)))
153 ;; device already has this file.
154 (unless (or (file-exists-p (concat device-directory target-file-name
))
158 (file-name-sans-extension target-file-name
) ".azw3")))
159 ;; converted temp file exist, when previous convert failed.
160 (if (file-exists-p convert-temp-file
)
162 (message "org-kindle: converted temp target file exist.")
163 (copy-file convert-temp-file device-directory
)
164 (message (format "org-kindle: %s finished." target-file-name
)))
165 ;; if source file format is matched for device, copy directly.
166 (if (or (string= (file-name-extension source-file
)
167 (file-name-extension target-file-name
))
168 ;; if source file is .azw3, also suitable for Kindle.
169 (if (equal (org-kindle--read-device-info) "kindle")
170 (string= (file-name-extension source-file
) "azw3")))
172 (copy-file (format "%s" source-file
) ; fix filename special characters like : etc in format.
173 (concat device-directory target-file-name
))
174 (message (format "org-kindle: %s finished." target-file-name
)))
175 ;; convert ebook to device compatible format.
176 (message (format "org-kindle: %s started..." target-file-name
))
177 ;; actually process to convert ebook
179 (concat "ebook-convert"
180 " " (shell-quote-argument source-file
)
181 " " (shell-quote-argument convert-temp-file
) " ; "
183 " " (shell-quote-argument convert-temp-file
)
184 " " device-directory
)
185 (format "*org-kindle: %s*" target-file-name
)
186 (format "*Error org-kindle: %s*" target-file-name
))
187 ;; write converted target file path to process output buffer.
188 (with-current-buffer (format "*org-kindle: %s*" target-file-name
)
189 (goto-char (point-max))
190 (insert (format "%s" (concat device-directory target-file-name
))))
194 ;; :name (format "org-kindle: %s" target-file-name)
196 ;; "ebook-convert" " "
197 ;; (shell-quote-argument source-file) " "
198 ;; (shell-quote-argument convert-temp-file))
199 ;; :sentinel (lambda (proc event)
200 ;; ;; send converted file to device
201 ;; (if (string= event "finished\n")
203 ;; (copy-file convert-temp-file device-directory)
204 ;; (message "org-kindle: %s finished." target-file-name))
205 ;; (user-error "Error on process: org-kindle.\n%S" event)))
206 ;; :buffer (format "*org-kindle: %s*" target-file-name))
212 (provide 'org-kindle
)
214 ;;; org-kindle.el ends here