packages feed

epub-tools-3.0: src/app/EpubTools/EpubMeta/Import.hs

-- License: ISC (see LICENSE)
-- Author: Dino Morelli <dino@ui3.info>

module EpubTools.EpubMeta.Import
   ( importOpf )
   where

import Codec.Archive.Zip ( Entry (..), addEntryToArchive, findEntryByPath
  , readEntry, toArchive )
import Codec.Epub.IO ( getPkgPathXmlFromBS, writeArchive )
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as BL
import Data.List ( foldl' )
import Data.Maybe ( fromJust )
import System.Directory ( removeFile )

import EpubTools.EpubMeta.Opts
import EpubTools.EpubMeta.Util


importOpf :: Options -> FilePath -> EM ()
importOpf opts zipPath = do
  -- The modified file we want to insert into the book
  let pathToNewOpf = fromJust . optImport $ opts

  -- Make new file into a Zip Entry
  tempEntry <- liftIO $ readEntry [] pathToNewOpf

  -- Read the zip archive in, we'll need it in several steps
  strictBytes <- liftIO $ BS.readFile zipPath

  -- The path in the book where new file must go
  (pathToOldFile, _) <- getPkgPathXmlFromBS strictBytes

  -- Adjust the entry's path
  let newOpfEntry = tempEntry { eRelativePath = pathToOldFile }

  -- Bytes of existing archive already loaded, make an Archive from that
  let oldArchive = toArchive . BL.fromChunks $ [strictBytes]

  -- Make an entry from the existing mimetype file
  mimeEntry <- maybe
    (throwError "Something went wrong: This epub has no mimetype, which shouldn't be possible. Original file unchanged.")
    return $ findEntryByPath "mimetype" oldArchive

  -- Add the two entries back to the archive in this order to preserve the
  -- mimetype as the first one
  let newArchive = foldl' (flip id) oldArchive
        [addEntryToArchive newOpfEntry, addEntryToArchive mimeEntry]

  -- We're ready to write the new zip archive, delete the old one
  liftIO $ removeFile zipPath

  -- Write the new archive out
  liftIO $ writeArchive zipPath newArchive