calibre.el/calibre-library.el

157 lines
5.7 KiB
EmacsLisp

;;; calibre-library.el --- View and interact with the Calibre library -*- lexical-binding:t -*-
;; Copyright (C) 2023 Free Software Foundation, Inc.
;; Author: Kjartan Oli Agustsson <kjartanoli@disroot.org>
;; Maintainer: Kjartan Oli Agustsson <kjartanoli@disroot.org>
;; This program is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;; View the contents of a Library, add new books, remove books, and
;; open books in Emacs.
;;; Code:
(require 'dired)
(require 'compat)
(require 'calibre-db)
(require 'calibre-book)
(require 'calibre-search)
(require 'calibre-virtual-library)
(require 'calibre-edit)
;;;###autoload
(defun calibre-library-add-book (file)
"Add FILE to the Calibre library."
(interactive "f")
(calibre-library-add-books (list file)))
(defun calibre-library-add-books (files)
"Add FILES to the Calibre library."
(calibre-exec--queue-command
`("add" "-r" ,@(mapcar #'expand-file-name files)))
(calibre-exec--start-execution))
;;;###autoload
(defun calibre-dired-add ()
"Add marked files to the Calibre library."
(interactive)
(if (derived-mode-p 'dired-mode)
(calibre-library-add-books (dired-get-marked-files))))
(defun calibre-library-remove-books (books)
"Remove BOOKS from the Calibre library."
(let ((ids (mapcar #'int-to-string (mapcar #'calibre-book-id books))))
(calibre-exec--queue-command `("remove" ,(string-join ids ",")))))
(defun calibre-library-mark-remove (&optional _num)
"Mark a book for removal and move to the next line."
(interactive "p" calibre-library-mode)
(tabulated-list-put-tag (char-to-string calibre-del-marker) t))
(defun calibre-library-mark-unmark (&optional _num)
"Clear any marks on a book and move to the next line."
(interactive "p" calibre-library-mode)
(let ((book (tabulated-list-get-id)))
(beginning-of-line)
(when (char-equal (char-after) ?M)
(calibre-edit-revert book))
(calibre-library--find-book book)
(tabulated-list-put-tag " " t)))
(defun calibre-library-execute ()
"Performed marked Library actions."
(interactive nil calibre-library-mode)
(let (remove-list modified-list)
(save-excursion
(goto-char (point-min))
(while (not (eobp))
(let ((book (tabulated-list-get-id))
(mark (char-after)))
(cond
((eql mark calibre-del-marker) (push book remove-list))
((eql mark calibre-mod-marker) (push book modified-list))))
(forward-line)))
(when remove-list (calibre-library-remove-books remove-list))
(when modified-list (calibre-edit-commit-edits modified-list)))
(calibre-library-revert)
(setf calibre-edit--edited-books nil)
(calibre-exec--start-execution)
(tabulated-list-clear-all-tags))
(defun calibre-library-revert (&rest _IGNORED)
"Revert the *LIBRARY* buffer."
(let ((pos (tabulated-list-get-id)))
(calibre-library--refresh t)
(if (not pos)
(goto-char (point-max))
(calibre-library--find-book pos))))
(defun calibre-library-open-book (book &optional arg)
"Open BOOK in its preferred format.
If called with a prefix argument prompt the user for the format."
(interactive (list (tabulated-list-get-id)
current-prefix-arg)
calibre-library-mode)
(let ((format (if arg
(completing-read "Format: " (calibre-book-formats book) nil t)
(calibre-book--pick-format book))))
(find-file (calibre-book--file book format))))
(defun calibre-library-open-book-other-window (book &optional arg)
"Open BOOK in its preferred format, in another window.
If called with a prefix argument prompt the user for the format."
(interactive (list (tabulated-list-get-id)
current-prefix-arg)
calibre-library-mode)
(let ((format (if arg
(completing-read "Format: " (calibre-book-formats book) nil t)
(calibre-book--pick-format book))))
(find-file-other-window (calibre-book--file book format))))
(defvar-keymap calibre-library-mode-map
:doc "Local keymap for Calibre Library buffers."
:parent tabulated-list-mode-map
"d" #'calibre-library-mark-remove
"u" #'calibre-library-mark-unmark
"e" #'calibre-edit-book
"x" #'calibre-library-execute
"a" #'calibre-library-add-book
"v" #'calibre-select-virtual-library
"s" #'calibre-search
"RET" #'calibre-library-open-book
"o" #'calibre-library-open-book-other-window)
(define-derived-mode calibre-library-mode tabulated-list-mode
"Library Mode"
(setf tabulated-list-padding 2
mode-line-process '(calibre-exec--commands ":Updating"))
(setq-local revert-buffer-function #'calibre-library-revert)
(setq-local font-lock-defaults
'(calibre-font-lock-keywords t nil nil beginning-of-line))
(calibre-library--set-header))
;;;###autoload
(defun calibre-library ()
"List all books in Calibre Library `calibrary-dir'."
(interactive)
(let ((buffer (get-buffer-create calibre-library-buffer)))
(with-current-buffer buffer
(calibre-library-mode)
(calibre-library--refresh t)
(display-buffer buffer))))
(provide 'calibre-library)
;;; calibre-library.el ends here