branch: externals/greader commit 38b4190780a475a974eec4bbc13c048ff1a0fd16 Author: Michelangelo Rodriguez <michelangelo.rodrig...@gmail.com> Commit: Michelangelo Rodriguez <michelangelo.rodrig...@gmail.com>
greader version 0.11.8 - greader-audiobook.el: Added support for converting buffers in m4b apple ebook format. - Some minor improvements. - Now greader-audiobook-buffer checks if the audiobook you want to - convert already exists and ask for further action. --- greader-audiobook.el | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++- greader.el | 2 +- 2 files changed, 116 insertions(+), 3 deletions(-) diff --git a/greader-audiobook.el b/greader-audiobook.el index 922bca81e4..2d1f3221a6 100644 --- a/greader-audiobook.el +++ b/greader-audiobook.el @@ -155,7 +155,10 @@ Only the final report will be printed." (defcustom greader-audiobook-pause-string "\n.\n.\n.\n.\n.\n" "The string that will be used to generate the pause at end of sentence." :type '(string)) - +(defcustom greader-audiobook-create-m4b nil + "If enabled, an m4b file will be created. +Enabling it implies disabling of the variable `greader-audiobook-compress'." + :type '(boolean)) ;; functions (defun greader-audiobook--percentage () @@ -306,6 +309,97 @@ COUNTER represents the current file name." (unless (eq result 0) (error "Error while compressing, see buffer *audiobook-zip* for more information")))) +(defun greader-audiobook--get-file-list () + "Return the list of media files in current dir. +Media files means that those files must have the same extension as +`greader-audiobook-transcode-format'." + + (let* ((regexp greader-audiobook-transcode-format) + (file-list (directory-files default-directory nil regexp))) + file-list)) + +(defun greader-audiobook--make-index () + "Write a file with all the tracks pertaining to this book." + (let* ((output-file-name "filelist.txt") + (file-list (greader-audiobook--get-file-list))) + (with-temp-buffer + (dolist (file file-list) + (insert "file " "\'" file "\'" "\n")) + (write-region (point-min) (point-max) output-file-name)))) + +(defun greader-audiobook--get-file-duration (file-name) + "Return the duration of FILE-NAME in milliseconds." + (with-temp-buffer + (let ((command "ffprobe") + (args (list "-i" file-name + "-show_entries" "format=duration" + "-v" "quiet" + "-of" "csv=p=0")) + (duration 0) + (process nil)) + (setq process (apply #'call-process command nil t nil args)) + (if (= process 0) + (progn + (goto-char (point-min)) + (unless (re-search-forward "[0-9]+\\.?[0-9]*" nil t) + (error "Cannot determine the duration of this file")) + (setq duration (match-string 0))) + (error + "There was an error while determining the duration of %s" + file-name)) + (truncate (* (string-to-number duration) 1000))))) + +(defun greader-audiobook--make-chapters-file () + "Create a file \=chapters.txt\= with our chapters. +This file should be compatible with ffmpeg." + + (let* ((output-file-name "chapters.txt") + (file-list (greader-audiobook--get-file-list)) + (title (file-name-sans-extension (buffer-name))) + (start 0) + (end 0)) + (with-temp-buffer + (insert + ";FFMETADATA1\n" + "artist=\n" + "title=" title "\n") + (dolist (file file-list) + (setq end + (+ (greader-audiobook--get-file-duration file) start)) + (insert + "\[CHAPTER\]\n" + "TIMEBASE=1/1000\n" + "START=" (number-to-string start) "\n" + "END=" (number-to-string end) "\n" + "title=" + (file-name-nondirectory (file-name-sans-extension file)) + "\n\n") + (setq start end)) + (write-region (point-min) (point-max) output-file-name)))) + +(defun greader-audiobook-make-m4b () + "Make an m4b file from the current folder." + (let* ((command "ffmpeg") + (output-file (concat + (expand-file-name + greader-audiobook-base-directory) + (file-name-sans-extension (buffer-name)) ".m4b")) + (args (list "-f" "concat" "-safe" "0" "-i" "filelist.txt" + "-i" "chapters.txt" "-map_metadata" "1" + "-f" "mp4" output-file)) + (output-buffer "*ffmpeg-m4b-output*") + (process nil) + (files-to-delete '("filelist.txt" "chapters.txt"))) + (greader-audiobook--make-index) + (greader-audiobook--make-chapters-file) + (setq process + (apply #'call-process command nil output-buffer nil args)) + (unless (eq process 0) + (error + "Error while creating m4b file. Please see %s for more information" + output-buffer)) + (mapc #'delete-file files-to-delete)) + t) ;;;###autoload (defun greader-audiobook-buffer (&optional start-position) @@ -318,6 +412,15 @@ This function will create a directory under buffer without the extension, if any." (interactive "P") + (when (directory-files greader-audiobook-base-directory nil + (file-name-sans-extension (buffer-name))) + (let ((response (yes-or-no-p "This audiobook already + exists. Overwrite it?"))) + (if response + (delete-directory (concat greader-audiobook-base-directory + (file-name-sans-extension (buffer-name))) + t t) + (user-error "Audiobook creation aborted by user")))) (unless greader-audiobook-buffer-quietly (message "Preparing for conversion (this could take some time...)")) (let ((end-position (point-max))) @@ -374,7 +477,16 @@ buffer without the extension, if any." (delete-file output-file-name))) (setq output-file-counter (+ output-file-counter 1))) (error "An error has occurred while converting"))) - (when greader-audiobook-compress + (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)) @@ -388,6 +500,7 @@ buffer without the extension, if any." (concat greader-audiobook-base-directory book-directory))))))) + (provide 'greader-audiobook) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; greader-audiobook.el ends here diff --git a/greader.el b/greader.el index 7b0e198921..c2b3f2095c 100644 --- a/greader.el +++ b/greader.el @@ -7,7 +7,7 @@ ;; Keywords: tools, accessibility ;; URL: https://gitlab.com/michelangelo-rodriguez/greader -;; Version: 0.11.7 +;; Version: 0.11.8 ;; 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