Today I Learned : Making ebooks

As far as I’m concerned, I always liked bash scripts. Even if, I’m not good at it, especially in remembering syntax and conditions… (yeah, I always have to check on internet…).

Years ago, I have wrote an article about the making of ebooks in epub format. This year I wanted to write a script able to zip or unzip a folder into epub format.

Note: Obviously, an easier way to manipulate epubs would be using calibre, sigil or - if you’re a terminal aficionado - pandoc.

Fiat e-book et facta est e-book

As I wrote in this previous article, with the zip command in your bash/zsh terminal, you can create an epub file easily:

# Zip Options:
# -x   exclude file
# -r   recurse into directories
# -D   do not add directory entries
# -9   compress better
# -X   eXclude eXtra file attributes
# -0   store only 

# create epub only with uncompressed mimetype:
zip -X0 <given ePub FilePath> mimetype
# add the other files to the epub:
zip -rDX9 <given ePub FilePath> * -x "*.DS_Store" -x mimetype

But to make this works properly you need to be sure that you have all the required files, the must important being the mimetype. With the following script, the e-book might not work if you’ve forgot the table of content or the container.xml file, but I stated that I’ll check only the mimetype’s presence.

RED='\033[0;31m'
NC='\033[0m' 
is_file(){
    [[ -n "$1" ]] && [[ -f "$1" ]] && return 0 || return 1
}
local current_path
current_path=$(pwd)
echo -n "Name of your ebook: "
read -r book_name
echo -n "Path to the book folders and files: "
read -r book_path
if [ -n "${book_path}" ] && [ -d "$book_path" ];then
   cd "$book_path" || return
   clean_dot # remove macOS ._ files
   if [ -n "${book_name}" ];then
   	local book=$book_name.epub
   	rm -f "$book"
   else
   	echo -e "${RED}A book name is required.${NC}"
   fi
   mimetype_file=$(find . -name "mimetype")
   if is_file "$mimetype_file";then
      zip_epub "$book" "$mimetype_file"
      mv "$book" "$current_path"/"$book"
      cd "$current_path" || return
   else
      echo -e "${RED}A mimetype file is required.${NC}"         
      echo "Please check if your folder contains the mimetype file."
    fi        
else
   echo -e "${RED}A path to the book files is required.${NC}"
   echo "Please check the path given."
fi  

To ease the creation, I ask the user the path of the book (read -r book_name) to change directory (cd "$book_path"), then I get the mimteype ($(find . -name "mimetype")).

You can improve the script to check the other required files, of course.

Dissecting the epub

We used the zip command to create an epub e-book. Well, I guess we can use unzip command to extract the files from the epub file?!

As unzip can’t extract directly from epub, I just needed to change epub extension to a zip one.

Basically, it’s cp file.epub file.zip. I could have used mv but I wanted to keep the epub file intact.

has_args(){
	[[ "$1" -ne 0 ]] && return 0 || return 1
}
if has_args $#;then
 	if [[ $1 == *.epub ]]; then
   		local folder_name="${1%%.*}" # get name without extension
   		cp "$1" "$folder_name".zip # bash cannot unzip epub directly
   		unzip -oq "$folder_name".zip -d "./${folder_name}"
   		rm -f "$folder_name".zip
 	fi
 else
 	echo -e "${RED}An error occurred.${NC}"
 fi
UNZIP options:
   	-o : force rewriting
   	-q : don't display whole process
   	-d : unzip in given folder

That’s all folks!

You can find a whole script integrating these “tools” on github.