module(...,package.seeall) local eb = require("tex4ebook-exec_epub") local dom = require("luaxml-domobject") local log = logging.new "exec_epub3" local ext = "xhtml" local outputdir = nil local input = nil function prepare(params) local basedir = params.input.."-".. params.format local outputdir_name="OEBPS" outputdir= basedir.."/"..outputdir_name input = params.input params.ext = ext params.tex4ht_sty_par = params.tex4ht_sty_par .. ",html5" params.packages = params.packages .. string.format("\\Configure{ext}{%s}",ext) return eb.prepare(params) end function run(out,params) return eb.run(out, params) end local function makeTOC(document) local template = [[ TOC ]] % {document=document} return template end local function add_media_overlays(content) local add_meta = function(package, attributes, text) local meta = package:create_element("meta",attributes) local dur_el = meta:create_text_node(text) meta:add_child_node(dur_el) package:add_child_node(meta) end -- calculate total audio time local calc_times = function(times) local time = 0 for _, curr in ipairs(times) do -- smil file contains timestamps in the H:M:S format, we need to parse it local hours, minutes, seconds = curr:match("(%d+):(%d+):(%d+)") time = time + os.time({year=1970, day=1, month=1, hour=hours, min=minutes, sec=seconds}) end return os.date("%H:%M:%S",time) end -- the second parameter for parse is table with void elements. the OPF format has no -- void elements, so it needs to be empty, otherwise we may get parsing error because of -- element, which is included in the default void elements local opfdom = dom.parse(content, {}) local items = opfdom:query_selector("manifest item") local ref = {} local times = {} local package = opfdom:query_selector("metadata")[1] -- we must read all smil files and find references to html files -- it is necessary to add media-overlay attribute to the referenced items for _, item in ipairs(items) do local href = item:get_attribute("href") ref[href] = item -- we must read audio length from the smil file and add it as a property if href:match("smil$") then local f = io.open(outputdir .. "/" .. href, "r") if not f then break end local smil = f:read("*all") f:close() local smildom = dom.parse(smil) local audios = smildom:query_selector("audio") local last = audios[#audios] -- add audio duration to the metadata section if last then local duration = last:get_attribute("clipend") if duration then -- todo: calculate total audio length table.insert(times, duration) local audio_id = item:get_attribute("id") add_meta(package, {property="media:duration", refines="#"..audio_id}, duration) end end -- add the media-overlay attribute local textref = smil:match('epub:textref="(.-)"') local id = item:get_attribute("id") local referenced = ref[textref] if referenced then referenced:set_attribute("media-overlay", id) end end end -- calculate length of all media overlay audio files if #times > 0 then local totaltime = calc_times(times) add_meta(package,{property="media:duration"}, totaltime) end local serialized = opfdom:serialize() return serialized end -- elements that shouldn't be put inside in TOC local stop_toc_processing_elements = { ol = true, ul = true } local function remove_spurious_TOC_elements(tocdom) local function count_child_elements(el) -- count children elements of the current element local count = 0 for _, curr_el in ipairs(el:get_children()) do if curr_el:is_element() then count = count + 1 end end return count end -- modify the TOC to comply to epubcheck tests -- add a blank
  • to empty
      for _, el in ipairs(tocdom:query_selector("ol")) do if count_child_elements(el) == 0 then el:remove_node() end end -- place child elements of the
    1. elements to an element, epubcheck reports -- error for text nodes that are direct child of
    2. for _, el in ipairs(tocdom:query_selector("li")) do local newa = el:create_element("a") local newchildren = {newa} -- we want to stop putting content as child of when it -- finds child TOC entries local keep_processing = true for i, child in ipairs(el._children) do child_name = child:get_element_name() -- put contents of
    3. to a new element if child:is_element() and child_name == "a" then -- set id and href of the new element, if it isn't set already if not newa:get_attribute("href") then local id = child:get_attribute("id") local href = child:get_attribute("href") newa:set_attribute("id", id) newa:set_attribute("href", href) end -- copy contents to the new element for _, x in ipairs(child._children or {}) do newa:add_child_node(x:copy_node()) end elseif stop_toc_processing_elements[child_name] then -- don't put child toc entries to the new keep_processing = false newchildren[#newchildren+1] = child elseif keep_processing == true then -- put every node before
        or