From 743d1b368f8c8bbd393454915f71a02453659423 Mon Sep 17 00:00:00 2001
From: John MacFarlane <jgm@berkeley.edu>
Date: Sat, 24 Nov 2018 20:34:54 -0800
Subject: [PATCH] EPUB writer: handle calibre metadata.

Nodes of the form

    <meta name="calibre:series" content="Classics on War and Politics"/>

are now included from an epub XML metadata file.  You can also
include this information in your YAML metadata, like so:

    calibre:
      series: Classics on War and Policitics

In addition, ibooks-specific metadata can now be included via
an XML file. (Previously, it could only be included via YAML
metadata, see #2693.)

Closes #5098.
---
 src/Text/Pandoc/Writers/EPUB.hs | 23 ++++++++++++++++++++++-
 1 file changed, 22 insertions(+), 1 deletion(-)

diff --git a/src/Text/Pandoc/Writers/EPUB.hs b/src/Text/Pandoc/Writers/EPUB.hs
index a4b841efd..93c685ffa 100644
--- a/src/Text/Pandoc/Writers/EPUB.hs
+++ b/src/Text/Pandoc/Writers/EPUB.hs
@@ -110,6 +110,7 @@ data EPUBMetadata = EPUBMetadata{
   , epubStylesheets   :: [FilePath]
   , epubPageDirection :: Maybe ProgressionDirection
   , epubIbooksFields  :: [(String, String)]
+  , epubCalibreFields :: [(String, String)]
   } deriving Show
 
 data Date = Date{
@@ -250,6 +251,18 @@ addMetadataFromXML e@(Element (QName name _ (Just "dc")) attrs _ _) md
   | name == "rights" = md { epubRights = Just $ strContent e }
   | otherwise = md
   where getAttr n = lookupAttr (opfName n) attrs
+addMetadataFromXML e@(Element (QName "meta" _ _) attrs _ _) md =
+  case getAttr "property" of
+       Just s | "ibooks:" `isPrefixOf` s ->
+                md{ epubIbooksFields = (drop 7 s, strContent e) :
+                       epubIbooksFields md }
+       _ -> case getAttr "name" of
+                 Just s | "calibre:" `isPrefixOf` s ->
+                   md{ epubCalibreFields =
+                         (drop 8 s, fromMaybe "" $ getAttr "content") :
+                          epubCalibreFields md }
+                 _ -> md
+  where getAttr n = lookupAttr (unqual n) attrs
 addMetadataFromXML _ md = md
 
 metaValueToString :: MetaValue -> String
@@ -333,6 +346,7 @@ metadataFromMeta opts meta = EPUBMetadata{
     , epubStylesheets        = stylesheets
     , epubPageDirection      = pageDirection
     , epubIbooksFields       = ibooksFields
+    , epubCalibreFields      = calibreFields
     }
   where identifiers = getIdentifier meta
         titles = getTitle meta
@@ -364,6 +378,10 @@ metadataFromMeta opts meta = EPUBMetadata{
                             Just (MetaMap mp)
                                -> M.toList $ M.map metaValueToString mp
                             _  -> []
+        calibreFields = case lookupMeta "calibre" meta of
+                            Just (MetaMap mp)
+                               -> M.toList $ M.map metaValueToString mp
+                            _  -> []
 
 -- | Produce an EPUB2 file from a Pandoc document.
 writeEPUB2 :: PandocMonad m
@@ -856,7 +874,7 @@ metadataElement version md currentTime =
   unode "metadata" ! [("xmlns:dc","http://purl.org/dc/elements/1.1/")
                      ,("xmlns:opf","http://www.idpf.org/2007/opf")] $ mdNodes
   where mdNodes = identifierNodes ++ titleNodes ++ dateNodes
-                  ++ languageNodes ++ ibooksNodes
+                  ++ languageNodes ++ ibooksNodes ++ calibreNodes
                   ++ creatorNodes ++ contributorNodes ++ subjectNodes
                   ++ descriptionNodes ++ typeNodes ++ formatNodes
                   ++ publisherNodes ++ sourceNodes ++ relationNodes
@@ -877,6 +895,9 @@ metadataElement version md currentTime =
                                             $ dateText x]
         ibooksNodes = map ibooksNode (epubIbooksFields md)
         ibooksNode (k, v) = unode "meta" ! [("property", "ibooks:" ++ k)] $ v
+        calibreNodes = map calibreNode (epubCalibreFields md)
+        calibreNode (k, v) = unode "meta" ! [("name", "calibre:" ++ k),
+                                             ("content", v)] $ ()
         languageNodes = [dcTag "language" $ epubLanguage md]
         creatorNodes = withIds "epub-creator" (toCreatorNode "creator") $
                        epubCreator md