branch: externals/greader
commit a0bc3fa176f30193d06e54d137aa8d41fa02377b
Author: Michelangelo Rodriguez <michelangelo.rodrig...@gmail.com>
Commit: Michelangelo Rodriguez <michelangelo.rodrig...@gmail.com>

    Now it’s possible to create an audiobook using `nov-mode`.
    
    The `greader-audiobook` framework is more flexible and allows the addition 
of modes that display their content by pages, not just continuously.
---
 greader-audiobook.el | 184 +++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 133 insertions(+), 51 deletions(-)

diff --git a/greader-audiobook.el b/greader-audiobook.el
index 3fd3d30332..fba6ee2945 100644
--- a/greader-audiobook.el
+++ b/greader-audiobook.el
@@ -64,6 +64,8 @@
 ;;; Code:
 (require 'subr-x)
 ;; variable definitions
+(require 'cl-lib)
+(require 'greader)
 (require 'greader-dict)
 (declare-function greader-dehyphenate nil)
 (declare-function greader-get-rate nil)
@@ -74,6 +76,18 @@
   "Greader audiobook configuration."
   :group 'greader)
 
+(defcustom greader-audiobook-count-blocks-modes-alist nil
+  "Alternative functions to count blocks for specific major modes.
+Each element of this alist is constituted by a major mode as its car,
+and a function to count blocks as its cdr.
+
+The function must return a number that expresses the number of blocks
+for a given buffer.
+For a use-case, please see the code, and in particular the function
+`greader-audiobook-nov-count-blocks."
+  :type
+  '(alist (symbol :tag "major mode") (function :tag "function")))
+
 (defcustom greader-audiobook-compress t
   "When enabled, compress the directory created using zip."
   :type '(boolean))
@@ -114,7 +128,51 @@ If you specify a function, that function has to return a 
cons in which
 car represents the start of the block, and cdr represents the end,
 or nil if there are no more blocks to convert."
   :type '(alist :key-type (symbol :tag "mode") :value-type (choice
-  (string  function))))
+                                                           (string
+                                                            function))))
+
+(defvar-local greader-audiobook--use-percentage t)
+
+(defvar greader-audiobook-after-convert-block-hook nil
+  "Functions to call after each block is converted.
+For example when the user needs to call a function to move to next
+chapter before getting the next block.")
+
+(defvar-local greader-audiobook-nov-document-counter 1
+  "Tracking of the current nov document that is being converted.")
+
+(with-eval-after-load 'nov
+  (defun greader-audiobook-nov-next-block ()
+    "Go to next block when in `nov-mode'."
+    (when (equal major-mode 'nov-mode)
+      (setq greader-audiobook--use-percentage nil)
+      (nov-next-document)
+      (setq greader-audiobook-nov-document-counter
+           (1+ greader-audiobook-nov-document-counter))))
+
+  (defun greader-audiobook-nov-get-block ()
+    "Get the block to read in `nov-mode'.
+
+If there are no more blocks, return nil."
+    (if (<= greader-audiobook-nov-document-counter (length
+                                                  nov-documents))
+       (cons (point-min) (point-max))
+      (setq greader-audiobook-nov-document-counter 1)
+      nil))
+
+  (defun greader-audiobook-nov-count-blocks ()
+    "Return total number of blocks in `nov-mode'."
+    (when (equal major-mode 'nov-mode)
+      (length nov-documents)))
+
+  (add-hook 'greader-audiobook-after-convert-block-hook
+           'greader-audiobook-nov-next-block)
+  (add-to-list 'greader-audiobook-modes
+              (cons 'nov-mode 'greader-audiobook-nov-get-block))
+  (add-to-list 'greader-audiobook-count-blocks-modes-alist (cons
+                                                           'nov-mode
+                                                           
'greader-audiobook-nov-count-blocks)))
+
 
 (defcustom greader-audiobook-transcode-wave-files nil
   "If enabled,  transcode original wave files using `ffmpeg'."
@@ -167,9 +225,13 @@ Enabling it implies disabling of the variable 
`greader-audiobook-compress'."
 
 (defun greader-audiobook--percentage ()
   "Return the percentage read of the buffer."
-  (let ((unit (/ (point-max) 100)))
-    (/ (point) unit)))
-(defun greader-audiobook--get-block ()
+  (let ((unit (/ (point-max) 100)) result)
+    (if greader-audiobook--use-percentage
+       (progn
+         (setq result (/ (point) unit))
+         (number-to-string result))
+      "n-a")))
+(cl-defun greader-audiobook--get-block ()
   "Get a block of text in current buffer.
 This function uses `greader-audiobook-block-size' to determine the
 position of the end of the block.
@@ -180,14 +242,22 @@ Return a cons with start and end of the block or nil if 
at end of the buffer."
   (save-excursion
     (let ((start (point))
          (end (point-max)))
-      (if (assq major-mode greader-audiobook-modes)
-         (progn
+      (if-let*
+         ((result (cdr (assq major-mode greader-audiobook-modes))))
+         (cond
+          ((functionp result)
+           (setq result (funcall result))
+           (unless result
+             (cl-return-from greader-audiobook--get-block nil))
+           (setq start (car result))
+           (setq end (cdr result)))
+          (t
            (when (looking-at "\\W")
              (setq start (re-search-forward "\\W*" nil 1)))
            (re-search-forward
             (cdr (assq major-mode greader-audiobook-modes))
             nil t 1)
-           (setq end (point)))
+           (setq end (point))))
        (pcase greader-audiobook-block-size
          ((pred numberp)
           (when (> greader-audiobook-block-size 0)
@@ -251,8 +321,16 @@ Return the generated file name, or nil if at end of the 
buffer."
          filename)
       nil)))
 
-(defun greader-audiobook--count-blocks ()
-  "Return the number of total blocks that constitutes a buffer."
+(cl-defun greader-audiobook--count-blocks ()
+  "Return the number of total blocks that constitutes a buffer.
+
+If the current `major-mode' is specified in
+`greader-audiobook-count-blocks-modes-alist', this function will
+return the value returned by the associated function."
+  (when-let* ((result (assoc major-mode
+                            greader-audiobook-count-blocks-modes-alist)))
+    (cl-return-from greader-audiobook--count-blocks
+      (funcall (cdr result))))
   (save-excursion
     (let ((blocks 0)
          (block (greader-audiobook--get-block)))
@@ -425,7 +503,8 @@ buffer without the extension, if any."
            (unless greader-audiobook-buffer-quietly
              (message "removing old audiobook..."))
            (delete-directory (concat greader-audiobook-base-directory
-                                     (file-name-sans-extension (buffer-name)))
+                                     (file-name-sans-extension
+                                      (buffer-name)))
                              t t))
        (user-error "Audiobook creation aborted by user"))))
   (unless greader-audiobook-buffer-quietly
@@ -466,46 +545,47 @@ buffer without the extension, if any."
            (unless greader-audiobook-buffer-quietly
              (message "converting block %d of %d \(%s\)"
                       output-file-counter
-                      total-blocks (concat (number-to-string
-                                            (greader-audiobook--percentage))
-                                           "\%")))
-           (setq output-file-name
-                 (greader-audiobook-convert-block output-file-name))
-           (if output-file-name
-               (progn
-                 (when greader-audiobook-transcode-wave-files
-                   (unless greader-audiobook-buffer-quietly
-                     (message "Transcoding block to %s..."
-                              greader-audiobook-transcode-format))
-                   (greader-audiobook-transcode-file
-                    output-file-name)
-                   (when
-                       greader-audiobook-cancel-intermediate-wave-files
-                     (delete-file output-file-name)))
-                 (setq output-file-counter (+ output-file-counter 1)))
-             (error "An error has occurred while converting")))
-         (when greader-audiobook-create-m4b
-           (unless greader-audiobook-buffer-quietly
-             (message "Building m4b..."))
-           (greader-audiobook-make-m4b)
+                      total-blocks (concat
+                                    (greader-audiobook--percentage)
+                      "\%")))
+         (setq output-file-name
+               (greader-audiobook-convert-block output-file-name))
+         (if output-file-name
+             (progn
+               (when greader-audiobook-transcode-wave-files
+                 (unless greader-audiobook-buffer-quietly
+                   (message "Transcoding block to %s..."
+                            greader-audiobook-transcode-format))
+                 (greader-audiobook-transcode-file
+                  output-file-name)
+                 (when
+                     greader-audiobook-cancel-intermediate-wave-files
+                   (delete-file output-file-name)))
+               (setq output-file-counter (+ output-file-counter 1)))
+           (error "An error has occurred while converting"))
+         (run-hooks 'greader-audiobook-after-convert-block-hook))
+       (when greader-audiobook-create-m4b
+         (unless greader-audiobook-buffer-quietly
+           (message "Building m4b..."))
+         (greader-audiobook-make-m4b)
+         (setq book-directory (concat (string-remove-suffix "/"
+                                                            book-directory)
+                                      ".m4b")))
+       (when
+           (and greader-audiobook-compress
+                (not greader-audiobook-create-m4b))
+         (setq default-directory greader-audiobook-base-directory)
+         (unless greader-audiobook-buffer-quietly
+           (message "compressing %s..." book-directory))
+         (greader-audiobook-compress book-directory)
+         (when greader-audiobook-compress-remove-original
+           (delete-directory book-directory t t)
            (setq book-directory (concat (string-remove-suffix "/"
                                                               book-directory)
-                                        ".m4b")))
-         (when
-             (and greader-audiobook-compress
-                  (not greader-audiobook-create-m4b))
-           (setq default-directory greader-audiobook-base-directory)
-           (unless greader-audiobook-buffer-quietly
-             (message "compressing %s..." book-directory))
-           (greader-audiobook-compress book-directory)
-           (when greader-audiobook-compress-remove-original
-             (delete-directory book-directory t t)
-             (setq book-directory (concat (string-remove-suffix "/"
-                                                                book-directory)
-                                          ".zip"))))
-         (message "conversion terminated and saved in %s"
-                  (concat greader-audiobook-base-directory
-                          book-directory)))))))
+                                        ".zip"))))
+       (message "conversion terminated and saved in %s"
+                (concat greader-audiobook-base-directory
+                        book-directory)))))))
 
 (defvar greader-audiobook-transcode-history nil)
 
@@ -516,14 +596,16 @@ original files will be deleted."
 
   (interactive
    (let ((book-directory (read-directory-name "Audiobook to
-re-transcode (directory): " greader-audiobook-base-directory nil t))
+re-transcode (directory): "
+                                             greader-audiobook-base-directory
+                                             nil t))
         (new-format (read-string "New format: " nil
-                                'greader-audiobook-transcode-history)))
+                                 'greader-audiobook-transcode-history)))
      (list book-directory new-format)))
   (let* ((default-directory audiobook-directory)
         (greader-audiobook-transcode-format new-format)
         (file-list (directory-files default-directory nil
-                                   "^[[:digit:]]")))
+                                    "^[[:digit:]]")))
     (dolist (file file-list)
       (unless greader-audiobook-buffer-quietly
        (message "Re-transcoding file %s..." file))

Reply via email to