Created
February 25, 2026 22:01
-
-
Save wa1kb0y/b68a5e6ab0d4e548d4d207554b693ff2 to your computer and use it in GitHub Desktop.
EPUB format fix for books exported from Apple Books
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| # This script is used to export epub books from iBooks / Mac Books and fix format to correct EPUB | |
| # What you find in the $ibooks_dir on iCloud are epubs that are zipped directories | |
| # This script will make them normal .epub files that you can use in other e-readers | |
| # I would advise to download your epubs from the iCloud to a folder on your desktop, there might also be pdf's in there | |
| # How to run: | |
| # Save this file as repackage_epubs.sh | |
| # Make executable in the terminal: chmod +x repackage_epubs.sh | |
| # ./repackage_epubs.sh -i # Use iBooks folder | |
| # ./repackage_epubs.sh -d /path # Use custom folder (absolute path) | |
| # ./repackage_epubs.sh # Use current directory | |
| # Function to build an EPUB file from an epub folder | |
| build_epub () | |
| { | |
| local source_folder="$1" # Input: folder | |
| local dest_file # Output: EPUB filename | |
| local output_dir="$2" # Output directory (absolute path) | |
| # Set output filename: use the folder name with .epub extension | |
| dest_file="${output_dir}/$(basename "${source_folder}").epub" | |
| # Enter the source folder (exit if failed) | |
| cd "${source_folder}" || { echo "Error: Could not enter ${source_folder}"; exit 1; } | |
| # Step 1: Add mimetype file to the EPUB with no compression (required by EPUB spec) | |
| zip --quiet -X0 "${dest_file}" mimetype || { echo "Error: Failed to add mimetype to ${dest_file}"; exit 1; } | |
| # Step 2: Add all other files with max compression, excluding .DS_Store and mimetype | |
| zip --quiet -rDX9 "${dest_file}" * -x "*.DS_Store" -x mimetype || { echo "Error: Failed to create ${dest_file}"; exit 1; } | |
| } | |
| # Main script | |
| main() | |
| { | |
| local search_dir="." # Default: recursive search current directory | |
| local ibooks_dir="~/Library/Mobile Documents/iCloud~com~apple~iBooks/Documents" | |
| local output_dir="output" | |
| # Create output directory if it doesn't exist | |
| mkdir -p "$output_dir" || { echo "Error: Could not create output directory"; exit 1; } | |
| # Get absolute path for output_dir | |
| output_dir="$(cd "$output_dir" && pwd)" | |
| # Parse command-line options | |
| while getopts "d:i" opt; do | |
| case "${opt}" in | |
| d) | |
| search_dir="${OPTARG}" | |
| ;; | |
| i) | |
| search_dir="$ibooks_dir" | |
| ;; | |
| *) | |
| echo "Usage: $0 [-d search_directory] [-i]" >&2 | |
| echo " -d: specify a custom search directory" >&2 | |
| echo " -i: use the default iBooks directory" >&2 | |
| exit 1 | |
| ;; | |
| esac | |
| done | |
| shift $((OPTIND - 1)) | |
| echo "Searching for .epub directories in: $search_dir" | |
| echo "Output will be saved in: $output_dir" | |
| # Find and process all .epub directories | |
| find "$search_dir" -type d -name \*.epub -print0 | | |
| while IFS= read -r -d '' epubdir; do | |
| # Check if a file with the same name as the directory does NOT exist in output_dir | |
| if [[ ! -f "${output_dir}/$(basename "$epubdir").epub" ]]; then | |
| echo "Processing $(basename "$epubdir")"; | |
| build_epub "$epubdir" "$output_dir"; | |
| else | |
| echo "Skipping $(basename "$epubdir") (output file already exists)"; | |
| fi; | |
| done | |
| } | |
| main "$@" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment