Upload library homepage
[org-kindle.git] / org-kindle.el
blobaafe886c6996bbdd483a35722a07471187d56afa
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)
12 ;; any later version.
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/>.
22 ;;; Commentary:
23 ;;;
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.
36 ;;; Todos:
38 ;; - Support sync Kindle notes with Org Mode notes file.
40 ;; Usage:
42 ;; [M-x org-kindle]
44 ;;; Code:
46 (require 'cl-lib) ; for `cl-case'
47 (require 'seq) ; for `seq-filter'
48 (require 'org)
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.."
54 :prefix "org-kindle-"
55 :group 'org)
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."
69 :type 'string
70 :group 'org-kindle)
72 ;;;###autoload
73 (defun org-kindle--read-device-info ()
74 "Match name in shell command lsusb listed out devices."
75 (cl-case system-type
76 ('darwin
77 (if (file-exists-p "/Volumes/kindle")
78 "kindle"
79 "unknown"))
80 ('gnu/linux
81 (cond
82 ((seq-filter
83 (lambda (usb)
84 (string-match (rx "Amazon Kindle") usb))
85 (split-string (shell-command-to-string "lsusb") "\n")) "kindle")
86 ((seq-filter
87 (lambda (usb)
88 (string-match (rx "Nook") usb))
89 (split-string (shell-command-to-string "lsusb") "\n")) "nook")
91 (progn
92 (warn "unknown device, can't detect device correctly,\n
93 please report to https://repo.or.cz/org-kindle.git")
94 "unknown"))))))
96 ;;;###autoload
97 (defun org-kindle--detect-format ()
98 "Detect plugged in device's ebook format."
99 (cl-case (intern (org-kindle--read-device-info))
100 ('kindle ".azw3")
101 ('nook ".epub")
102 (t org-kindle-default-format)))
104 ;;;###autoload
105 (defun org-kindle--mount-path ()
106 "Get Linux general mount path."
107 (cl-case system-type
108 ('gnu/linux
109 (directory-file-name (concat "/run/media/" (getenv "USER"))))
110 ('darwin
111 (directory-file-name "/Volumes/"))
112 ('windows-nt ; TODO:
115 ;;;###autoload
116 (defun org-kindle--detect-directory ()
117 "Detect plugged in device directory of saving ebook."
118 (cl-case (intern (org-kindle--read-device-info))
119 ('kindle
120 (expand-file-name
121 (concat (org-kindle--mount-path)
122 (plist-get (plist-get org-kindle-supported-devices-alist :kindle)
123 :documents-path))))
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."
129 (->> 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."
136 (->> filename
137 (replace-regexp-in-string ":" "-")))
139 ;;;###autoload
140 (defun org-kindle-send-to-device ()
141 "Send `org-mode' ebook file: link to external devices with corresponding formats."
142 (interactive)
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))
155 (file-exists-p
156 (concat
157 device-directory
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)
161 (progn
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")))
171 (progn
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
178 (async-shell-command
179 (concat "ebook-convert"
180 " " (shell-quote-argument source-file)
181 " " (shell-quote-argument convert-temp-file) " ; "
182 "cp"
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))))
192 ;; FIXME:
193 ;; (make-process
194 ;; :name (format "org-kindle: %s" target-file-name)
195 ;; :command (list
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")
202 ;; (progn
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))
208 ))))))
212 (provide 'org-kindle)
214 ;;; org-kindle.el ends here