aboutsummaryrefslogtreecommitdiff
path: root/emacs/.emacs.d/lisp/my/belf.el
diff options
context:
space:
mode:
authorYuchen Pei <id@ypei.org>2025-02-07 09:52:11 +1100
committerYuchen Pei <id@ypei.org>2025-02-07 09:52:11 +1100
commit1302f96df75f4f93247beaafee0b0a780829be18 (patch)
tree7ae569f3ce8d16d386bd02882491b0e02ff8f2af /emacs/.emacs.d/lisp/my/belf.el
parent2f880075e7adc9c8070e5b0e606af7fbf78eaa0a (diff)
[emacs] Flesh out bookshelf mode a bitHEADmaster
Add follow mode. Display book cover in infobox. Render html description in infobox.
Diffstat (limited to 'emacs/.emacs.d/lisp/my/belf.el')
-rw-r--r--emacs/.emacs.d/lisp/my/belf.el89
1 files changed, 85 insertions, 4 deletions
diff --git a/emacs/.emacs.d/lisp/my/belf.el b/emacs/.emacs.d/lisp/my/belf.el
index 035f44d..89f27c0 100644
--- a/emacs/.emacs.d/lisp/my/belf.el
+++ b/emacs/.emacs.d/lisp/my/belf.el
@@ -31,9 +31,14 @@
(defvar-keymap belf-mode-map
:parent tabulated-list-mode-map
- "i" #'belf-book-infobox
+ "F" #'belf-toggle-follow-mode
+ "d" #'belf-show-in-dired
+ "i" #'belf-book-infobox-at-point
+ "n" #'belf-next-line
+ "o" #'belf-open-book-other-window
+ "p" #'belf-previous-line
"RET" #'belf-open-book
- "o" #'belf-open-book-other-window)
+ )
(define-derived-mode belf-mode tabulated-list-mode "Bookshelf"
"Major mode for browsing a list of books."
@@ -77,9 +82,85 @@
(title . ,(match-string 2 base))
(year . ,(match-string 3 base))))))
-(defun belf-book-infobox ()
+(defun belf-book-infobox (file-name)
(interactive)
- (infobox-exiftool (tabulated-list-get-id)))
+ (belf-book-render-info (belf-exiftool-info file-name) file-name))
+
+(defvar belf-exiftool-program "exiftool" "The exiftool program.")
+
+(defun belf-exiftool-info (file-name)
+ "Given a video URL, return an alist of its properties."
+ (with-temp-buffer
+ (call-process belf-exiftool-program nil t nil "-j" file-name)
+ (let ((start (point)))
+ (call-process-region
+ nil nil "jq" nil t nil
+ ".[0]|pick(.Title, .Author, .Creator, .Keywords, .Subject, .Publisher, .Identifier, .Series, .Title_sort, .Author_sort, .PageCount, .ISBN, .Language, .FileType, .Description)")
+ (goto-char start)
+ (json-read)))
+ )
+
+(defun belf-book-cover (file-name)
+ "Get book cover.
+
+First look for an image file with the same file name.
+Then for PDF, extract the first page.
+For EPUB, looks for a cover image in the file. If not found, extract the first page."
+ (cond ((file-exists-p (file-name-with-extension file-name "jpg"))
+ (format "file://%s" (file-name-with-extension file-name "jpg")))
+ (t nil)))
+
+(defun belf-book-infobox-at-point ()
+ (interactive)
+ (let ((help-window-select (not belf-follow-mode)))
+ (belf-book-infobox (tabulated-list-get-id)))
+ )
+
+(defun belf-book-render-info (info file-name)
+ (setf (alist-get 'Title info)
+ (concat (alist-get 'Title info)
+ " -- "
+ (buttonize
+ "xdg-open"
+ (lambda (_) (call-process "xdg-open" nil 0 nil file-name)))
+ " " (buttonize "find-file" (lambda (_) (find-file file-name))))
+ (alist-get 'Thumbnail info)
+ (belf-book-cover file-name)
+ (alist-get 'Description info)
+ (when-let ((text (alist-get 'Description info)))
+ (with-temp-buffer
+ (insert text)
+ (shr-render-region (point-min) (point-max))
+ (goto-char (point-min))
+ (insert "\n")
+ (buffer-string))))
+ (infobox-render
+ (infobox-translate info (infobox-default-specs info))
+ `(belf-book-infobox ,file-name)
+ (called-interactively-p 'interactive)))
+
+(defvar belf-follow-mode nil "Whether follow mode is on.")
+
+(defun belf-toggle-follow-mode ()
+ (interactive)
+ (setq belf-follow-mode (not belf-follow-mode)))
+
+
+(defun belf-previous-line ()
+ (interactive)
+ (previous-line)
+ (when belf-follow-mode
+ (belf-book-infobox-at-point)))
+
+(defun belf-next-line ()
+ (interactive)
+ (next-line)
+ (when belf-follow-mode
+ (belf-book-infobox-at-point)))
+
+(defun belf-show-in-dired ()
+ (interactive)
+ (dired-jump-other-window (tabulated-list-get-id)))
(defun belf-open-book ()
(interactive)