Answers.Body: <pre><code>zip -X0 "my.epub" "mimetype"
  zip -Xr "my.epub" "META-INF/" "OEBPS/"
  </code></pre>
  
  <p>As palacsint already pointed out, without the -X flag, one would run into the epubcheck error PKG_005</p>
  
  <pre><code>"The mimetype file has an extra field of length %1$s. The use of the extra field feature of the ZIP format is not permitted for the mimetype file."
  </code></pre>
  
  <p>because the mimetype file is being used as magical number within the compressed zip file, and the zip extra field feature (where zip programs and operating systems can place non-standardized data) would destroy the magical number mechanism (see <a href="https://github.com/IDPF/epubcheck/pull/497" rel="noreferrer">https://github.com/IDPF/epubcheck/pull/497</a>). The -0 flag makes sure that the mimetype file doesn't get compressed, which is also necessary for the mimetype file to work as a magical number, otherwise the data at the position where the mimetype file is expected could be compressed, scrambled gibberish.</p>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2015-09-19T09:18:30.967Z
Answers.LastActivityDate: 2015-09-19T09:18:30.967Z
Answers.UserDisplayName: skreutzer
Answers.Body: <p>A one-liner based on the previous answers, which will take the current dirname as the epub name, and the contents of the current dir as the epub: <code>zip -rX "../$(basename "$(realpath .)").epub" mimetype $(ls|xargs echo|sed 's/mimetype//g')</code></p>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-02-21T20:24:45.793Z
Answers.Text: On a Mac, `realpath` is not available by default and you'll want to exclude the invisible `.DS_Store` files… Making the command: `zip -rX "../myprecious.epub" mimetype $(ls|xargs echo|sed 's/mimetype//g') -x *.DS_Store`.
Answers.UserDisplayName: Fabien Snauwaert
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2023-03-04T16:46:23.510Z
Answers.Text: To exclude any DS_Store in any directory use this pattern with the answer from @FabienSnauwaert `**/.DS_Store`
Answers.UserDisplayName: ow3n
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2017-06-26T02:01:09.603Z
Answers.LastActivityDate: 2017-06-26T02:01:09.603Z
Answers.UserDisplayName: geek1011
Answers.Body: <p>I'm using this python script to batch repackage the files.</p>
  <pre><code>import os
  import shutil
  import zipfile
  
  # Enter the paths
  path_to_files = &quot;/Users/matteo/Desktop/ebooks&quot;   # Path to directory containing epub packages
  path_to_new_files = &quot;/Users/matteo/Desktop/ebooks_conv&quot;   # Path to store new epub files in
  
  # Function to store all filenames in a list
  def extract_filename(path_to_files):
      filenames = []
      for f in os.listdir(path_to_files):
          f_name, f_ext = os.path.splitext(f)
          if f_ext == &quot;.epub&quot;:
              filenames.append(f_name)
      filenames.sort()
      return filenames
  
  # Function to generate new epub files
  def create_epub(filenames, path_to_files, path_to_new_files):
      total_files = len(filenames)
      for i, filename in enumerate(filenames, 1):
          epub_path = os.path.join(path_to_files, filename + &quot;.epub&quot;)
          
          # Remove iTunesMetadata.plist if exists
          plist_path = os.path.join(path_to_files, &quot;iTunesMetadata.plist&quot;)
          if os.path.exists(plist_path):
              os.remove(plist_path)
          
          # Copy the EPUB files to a temporary directory to avoid zipping recursively
          temp_dir = os.path.join(path_to_new_files, filename)
          shutil.copytree(epub_path, temp_dir)
          
          # Create the new EPUB archive
          with zipfile.ZipFile(os.path.join(path_to_new_files, filename + &quot;.epub&quot;), 'w') as new_epub:
              for root, dirs, files in os.walk(temp_dir):
                  for file in files:
                      file_path = os.path.join(root, file)
                      # Write each file to the archive
                      new_epub.write(file_path, os.path.relpath(file_path, temp_dir))
          
          # Clean up the temporary directory
          shutil.rmtree(temp_dir)
          
          print(&quot;File #&quot;, i, &quot; has been processed successfully. Remaining files:&quot;, total_files - i)
  
  filenames = extract_filename(path_to_files)
  create_epub(filenames, path_to_files, path_to_new_files)
  </code></pre>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2024-04-18T11:20:33.580Z
Answers.LastActivityDate: 2024-04-18T11:20:33.580Z
Answers.UserDisplayName: Matteo Curcio
Answers.Body: <pre><code>zip -rX ../my.epub mimetype META-INF/ OEBPS/
  </code></pre>
  
  <hr>
  
  <p>Without <code>-X</code> you could get the following when validating it with EpubCheck:</p>
  
  <pre><code>ERROR: my.epub: Mimetype entry must not have an extra field in its ZIP header
  </code></pre>
  
  <p>If <code>mimetype</code> is not the first in the <code>epub</code> file EpubCheck prints the following:</p>
  
  <pre><code>ERROR: my.epub: Mimetype entry missing or not the first in archive
  </code></pre>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2013-12-21T11:11:21.237Z
Answers.LastActivityDate: 2013-12-21T11:11:21.237Z
Answers.UserDisplayName: palacsint
Body: <p>I unzipped an <code>epub</code> file to make some minor modifications. How can I repack it properly to be a valid <code>epub</code> file from command line on Linux?</p>
  
Tags: <epub><linux>
Title: How to repack an epub file from command line
UserDisplayName: palacsint
ThreadText: # How to repack an epub file from command line
  
  (Asked by: username_0 on 2013-12-21)
  
  I unzipped an `epub` file to make some minor modifications. How can I repack it properly to be a valid `epub` file from command line on Linux?
  
  **Tags:** epub, linux
  
  
  ---
  
  ## 4 answers
  
  ### Answer by username_0 on 2013-12-21. Score: 33 | Accepted answer
  
  zip -rX ../my.epub mimetype META-INF/ OEBPS/
  
  
  Without -X you could get the following when validating it with EpubCheck:
  ERROR: my.epub: Mimetype entry must not have an extra field in its ZIP header
  
  If mimetype is not the first in the epub file EpubCheck prints the following:
  ERROR: my.epub: Mimetype entry missing or not the first in archive
  
  
  ---
  
  ### Answer by username_1 on 2015-09-19. Score: 7
  
  zip -X0 "my.epub" "mimetype"
  zip -Xr "my.epub" "META-INF/" "OEBPS/"
  
  As username_0 already pointed out, without the -X flag, one would run into the epubcheck error PKG_005
  "The mimetype file has an extra field of length %1$s. The use of the extra field feature of the ZIP format is not permitted for the mimetype file."
  
  because the mimetype file is being used as magical number within the compressed zip file, and the zip extra field feature (where zip programs and operating systems can place non-standardized data) would destroy the magical number mechanism (see https://github.com/IDPF/epubcheck/pull/497). The -0 flag makes sure that the mimetype file doesn't get compressed, which is also necessary for the mimetype file to work as a magical number, otherwise the data at the position where the mimetype file is expected could be compressed, scrambled gibberish.
  
  
  ---
  
  ### Answer by username_2 on 2017-06-26. Score: 2
  
  A one-liner based on the previous answers, which will take the current dirname as the epub name, and the contents of the current dir as the epub: `zip -rX "../$(basename "$(realpath .)").epub" mimetype $(ls|xargs echo|sed 's/mimetype//g')`
  
  > **Comments:**
  > **username_3**: On a Mac, `realpath` is not available by default and you'll want to exclude the invisible `.DS_Store` files… Making the command: `zip -rX "../myprecious.epub" mimetype $(ls|xargs echo|sed 's/mimetype//g') -x *.DS_Store`.  
  > **username_4**: To exclude any DS_Store in any directory use this pattern with the answer from @FabienSnauwaert `**/.DS_Store`  
  
  ---
  
  ### Answer by username_5 on 2024-04-18. Score: 0
  
  I'm using this python script to batch repackage the files.
  import os
  import shutil
  import zipfile
  
  # Enter the paths
  path_to_files = "/Users/matteo/Desktop/ebooks"   # Path to directory containing epub packages
  path_to_new_files = "/Users/matteo/Desktop/ebooks_conv"   # Path to store new epub files in
  
  # Function to store all filenames in a list
  def extract_filename(path_to_files):
      filenames = []
      for f in os.listdir(path_to_files):
          f_name, f_ext = os.path.splitext(f)
          if f_ext == ".epub":
              filenames.append(f_name)
      filenames.sort()
      return filenames
  
  # Function to generate new epub files
  def create_epub(filenames, path_to_files, path_to_new_files):
      total_files = len(filenames)
      for i, filename in enumerate(filenames, 1):
          epub_path = os.path.join(path_to_files, filename + ".epub")
          
          # Remove iTunesMetadata.plist if exists
          plist_path = os.path.join(path_to_files, "iTunesMetadata.plist")
          if os.path.exists(plist_path):
              os.remove(plist_path)
          
          # Copy the EPUB files to a temporary directory to avoid zipping recursively
          temp_dir = os.path.join(path_to_new_files, filename)
          shutil.copytree(epub_path, temp_dir)
          
          # Create the new EPUB archive
          with zipfile.ZipFile(os.path.join(path_to_new_files, filename + ".epub"), 'w') as new_epub:
              for root, dirs, files in os.walk(temp_dir):
                  for file in files:
                      file_path = os.path.join(root, file)
                      # Write each file to the archive
                      new_epub.write(file_path, os.path.relpath(file_path, temp_dir))
          
          # Clean up the temporary directory
          shutil.rmtree(temp_dir)
          
          print("File #", i, " has been processed successfully. Remaining files:", total_files - i)
  
  filenames = extract_filename(path_to_files)
  create_epub(filenames, path_to_files, path_to_new_files)
  
  
  ---
  
  