branch: externals/calibre
commit 4b6af65d08e4130c2fbd829a7bd037ab11e6df73
Author: Kjartan Óli Ágústsson <[email protected]>
Commit: Kjartan Óli Ágústsson <[email protected]>

    Support editing book metadata
    
    * calibre-edit.el (eieio-custom):
    (calibre-db):
    (calibre-util):
    (calibre-exec):
    (calibre-edit--edited-books):
    (calibre-edit-book):
    (eieio-done-customizing):
    (calibre-edit-revert):
    (calibre-edit--find-original):
    (calibre-edit--different-fields):
    (calibre-util-uglify-field-name):
    (calibre-edit--command):
    (calibre-edit-commit-edits):
    (calibre-edit):
    Add
    * calibre-library.el:
    (calibre-library-mark-unmark): Undo edits if mark is M.
    (calibre-library-mode-map): Bind e to calibre-edit-book.
    (calibre-library-execute): Commit edits when executing.
---
 calibre-edit.el    | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 calibre-library.el | 36 +++++++++++----------
 2 files changed, 112 insertions(+), 16 deletions(-)

diff --git a/calibre-edit.el b/calibre-edit.el
new file mode 100644
index 0000000000..8145726344
--- /dev/null
+++ b/calibre-edit.el
@@ -0,0 +1,92 @@
+;;; calibre-edit.el --- Edit Book metadata  -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2023  Kjartan Oli Agustsson
+
+;; This file is part of calibre.el.
+
+;; calibre.el 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.
+
+;; calibre.el 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 calibre.el.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Code:
+(require 'eieio-custom)
+(require 'calibre-db)
+(require 'calibre-util)
+(require 'calibre-exec)
+
+(defvar calibre-edit--edited-books nil
+  "A list containing the original copies of edited books.")
+
+(defun calibre-edit-book (book)
+  "Edit the metadata of BOOK."
+  (interactive (list (tabulated-list-get-id)) calibre-library-mode)
+  (unless (calibre-util-find-book book calibre-edit--edited-books)
+    (push (clone book) calibre-edit--edited-books))
+  (eieio-customize-object book))
+
+(cl-defmethod eieio-done-customizing ((book calibre-book))
+  (calibre-library--refresh)
+  (with-current-buffer (get-buffer calibre-library-buffer)
+    (calibre-library--find-book book)
+    (tabulated-list-put-tag "M")))
+
+(defun calibre-edit-revert (book)
+  "Undo any edits performed to BOOK in this session."
+  (let ((compare-ids (lambda (b)
+                            (= (calibre-book-id book)
+                               (calibre-book-id b)))))
+    (setf calibre--books
+        (cl-substitute-if (calibre-util-find-book book 
calibre-edit--edited-books)
+                          compare-ids
+                          calibre--books))
+    (calibre-library--refresh)))
+
+(defun calibre-edit--find-original (book)
+  "Return BOOK absent any modifications performed in this session."
+  (calibre-util-find-book book calibre-edit--edited-books))
+
+(defun calibre-edit--different-fields (a b)
+  "Return a list of slot names whose values differ in A and B."
+  (let (diff)
+    (dolist (descriptor (eieio-class-slots 'calibre-book))
+      (let* ((slot-name (eieio-slot-descriptor-name descriptor))
+             (a (slot-value a slot-name))
+             (b (slot-value b slot-name)))
+        (unless (equal a b)
+          (push slot-name diff))))
+    diff))
+
+(defun calibre-util-uglify-field-name (field)
+  "Return FIELD replacing - with -."
+  (string-join (split-string (symbol-name field) "-") "_"))
+
+(defun calibre-edit--command (book)
+  "Return the command to commit edits to BOOK to disk."
+  `("set_metadata"
+    ,@(flatten-list (mapcar (lambda (field)
+                              `("-f" ,(format "%s:%s" 
(calibre-util-uglify-field-name field)
+                                             (cl-case field
+                                               (authors (string-join 
(calibre-book-authors book) ","))
+                                               (title (calibre-book-title 
book))
+                                               (publisher 
(calibre-book-publisher book))
+                                               (series (calibre-book-series 
book))
+                                               (series-index 
(calibre-book-series-index book))
+                                               (tags (string-join 
(calibre-book-tags book) ","))))))
+                           (calibre-edit--different-fields book 
(calibre-edit--find-original book))))
+    ,(format "%d" (calibre-book-id book))))
+
+(defun calibre-edit-commit-edits (books)
+  "Commit edits to BOOKS to disk."
+  (calibre-exec--queue-commands (mapcar #'calibre-edit--command books)))
+
+(provide 'calibre-edit)
+;;; calibre-edit.el ends here
diff --git a/calibre-library.el b/calibre-library.el
index a9f5765b91..546cf92d34 100644
--- a/calibre-library.el
+++ b/calibre-library.el
@@ -28,6 +28,7 @@
 (require 'calibre-book)
 (require 'calibre-search)
 (require 'calibre-virtual-library)
+(require 'calibre-edit)
 
 ;;;###autoload
 (defun calibre-library-add-book (file)
@@ -59,32 +60,34 @@
   (tabulated-list-put-tag "D" t))
 
 (defun calibre-library-mark-unmark (&optional _num)
-  "Clear any mark on a book and move to the next line."
+  "Clear any marks on a book and move to the next line."
   (interactive "p" calibre-library-mode)
-  (tabulated-list-put-tag " " t))
+  (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 mark)
+  (let (remove-list modified-list mark)
     (save-excursion
       (goto-char (point-min))
       (while (not (eobp))
         (setf mark (char-after))
-        (cl-case mark
-          (?\D (push (tabulated-list-get-id) remove-list)))
+        (let ((book (tabulated-list-get-id)))
+          (cl-case mark
+            (?D (push book remove-list))
+            (?M (push book modified-list))))
         (forward-line)))
-    (when remove-list (calibre-library-remove-books remove-list)))
-  (calibre--books t)
-  (calibre-library--refresh))
-
-(defun calibre-library--find-book (book)
-  "Move point to the line representing BOOK."
-  (goto-char (point-min))
-        (while (not (or (eobp)
-                        (= (calibre-book-id (tabulated-list-get-id))
-                           (calibre-book-id book))))
-          (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)
   (let ((pos (tabulated-list-get-id)))
@@ -108,6 +111,7 @@
   :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

Reply via email to