Current section
Files
Jump to
Current section
Files
lib/metadata/epub.ex
defmodule ExEbook.Metadata.Epub do
@moduledoc """
Module for handling metadata information for EPUB files
"""
@type path :: charlist()
require Logger
use ExEbook.Converter
alias ExEbook.{Xml, Zip}
@root_file "META-INF/container.xml"
@impl true
def read_file(path) do
case Zip.open_file_in_memory(path) do
{:ok, zip_pid} ->
open_root_file(zip_pid)
_ ->
{:error, :invalid_type}
end
end
@impl true
def extract_metadata(data) do
data
|> Xml.read_document()
|> Xml.find_elements('/package/metadata/dc:*')
|> to_map(&generate_map/2)
end
@impl true
def transform(information) do
%Metadata{}
# isbn
|> add_identifier(information, "identifier")
|> add_title(information, "title")
|> add_language(information, "language")
# creator
|> add_authors(information, "creator")
# publisher
|> add_creator(information, "publisher")
|> add_subject(information, "subject")
end
@impl true
def extract_image(path) do
with {:ok, zip_pid} <- Zip.open_file_in_memory(path),
{:ok, document} <- open_root_file(zip_pid) do
document
|> Xml.read_document()
|> fetch_cover(zip_pid)
end
end
defp open_root_file(zip_pid) do
case open_file(@root_file, zip_pid) do
{:ok, document} ->
document
|> fetch_root_file_path()
|> open_file(zip_pid)
error ->
Logger.error("EROR opening root file #{inspect(error)}")
error
end
end
defp fetch_root_file_path(document) do
document
|> Xml.read_document()
|> from_document_extract_attrs('//rootfile/@full-path')
end
defp open_file(file_path, zip_pid) do
case Zip.read_in_memory_file(zip_pid, file_path) do
{:ok, document} ->
{:ok, document}
:error ->
{:error, :epub_read}
end
end
defp generate_map(node, map) do
Map.put(map, key_name(node), node_text(node))
end
defp key_name(node) do
node
|> elem(3)
|> elem(1)
|> to_string()
end
defp node_text(node) do
node
|> Xml.find_elements('./text()')
|> Xml.text()
end
defp fetch_cover(document, zip_pid) do
document
|> find_item_name()
|> find_item(document)
|> open_file(zip_pid)
end
defp find_item_name(document) do
from_document_extract_attrs(document, '//meta[@name="cover"]/@content')
end
defp find_item(item_name, document) do
from_document_extract_attrs(document, '//manifest/item[@id="#{item_name}"]/@href')
end
defp from_document_extract_attrs(document, elements) do
document
|> Xml.find_elements(elements)
|> Xml.extract_attr()
end
end