X-Git-Url: https://git.mdrn.pl/wl-app.git/blobdiff_plain/48b2fe9f7c2dc3d9aeaaa6dbfb27c7da4f3235ff..269195b3729c1bdc22e9053ee4ebca667ea8549d:/Android/r2-streamer/r2-parser/src/main/java/org/readium/r2_streamer/parser/MediaOverlayParser.java diff --git a/Android/r2-streamer/r2-parser/src/main/java/org/readium/r2_streamer/parser/MediaOverlayParser.java b/Android/r2-streamer/r2-parser/src/main/java/org/readium/r2_streamer/parser/MediaOverlayParser.java new file mode 100755 index 0000000..4b7a34e --- /dev/null +++ b/Android/r2-streamer/r2-parser/src/main/java/org/readium/r2_streamer/parser/MediaOverlayParser.java @@ -0,0 +1,200 @@ +package org.readium.r2_streamer.parser; + +import org.readium.r2_streamer.model.container.Container; +import org.readium.r2_streamer.model.publication.EpubPublication; +import org.readium.r2_streamer.model.publication.SMIL.MediaOverlayNode; +import org.readium.r2_streamer.model.publication.SMIL.SMILParser; +import org.readium.r2_streamer.model.publication.link.Link; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import java.util.List; + +/** + * Created by gautam chibde on 31/5/17. + */ + +public class MediaOverlayParser { + + /** + * Looks for the link with type: application/smil+xml and parsed the + * data as media-overlay + * also adds link for media-overlay for specific file + * + * @param publication The `Publication` object resulting from the parsing. + * @param container contains implementation for getting raw data from file + * @throws EpubParserException if file is invalid for not found + */ + public static void parseMediaOverlay(EpubPublication publication, Container container) throws EpubParserException { + for (String key : publication.linkMap.keySet()) { + if (publication.linkMap.get(key).typeLink.equalsIgnoreCase("application/smil+xml")) { + Link link = publication.linkMap.get(key); + String smip = container.rawData(link.getHref()); + if (smip == null) return; // maybe file is invalid + + Document document = EpubParser.xmlParser(smip); + + if (document == null) + throw new EpubParserException("Error while parsing file " + link.href); + + Element body = (Element) document.getDocumentElement().getElementsByTagName("body").item(0); + + MediaOverlayNode node = new MediaOverlayNode(); + node.role.add("section"); + + if (body.hasAttribute("epub:textref")) + node.text = body.getAttribute("epub:textref"); + + parseParameters(body, node, link.href); + parseSequences(body, node, publication, link.href); + + // TODO + // Body attribute epub:textref is optional + // ref https://www.idpf.org/epub/30/spec/epub30-mediaoverlays.html#sec-smil-body-elem + // need to handle parsing in an alternate way + + if (node.text != null) { + String baseHref = node.text.split("#")[0]; + int position = getPosition(publication.spines, baseHref); + + if (position != -1) { + addMediaOverlayToSpine(publication, node, position); + } + } else { + for (MediaOverlayNode node1 : node.children) { + int position = getPosition(publication.spines, node1.text); + if (position != -1) { + addMediaOverlayToSpine(publication, node1, position); + } + } + } + } + } + } + + /** + * [RECURSIVE] + *

+ * Parse the elements at the current XML level. It will recursively + * parse their children's and + * + * @param body input element with seq tag + * @param node contains parsed elements + * @param href path of SMIL file + */ + private static void parseSequences(Element body, MediaOverlayNode node, EpubPublication publication, String href) throws StackOverflowError { + if (body == null || !body.hasChildNodes()) { + return; + } + for (Node n = body.getFirstChild(); n != null; n = n.getNextSibling()) { + if (n.getNodeType() == Node.ELEMENT_NODE) { + Element e = (Element) n; + if (e.getTagName().equalsIgnoreCase("seq")) { + MediaOverlayNode mediaOverlayNode = new MediaOverlayNode(); + + if (e.hasAttribute("epub:textref")) + mediaOverlayNode.text = e.getAttribute("epub:textref"); + + mediaOverlayNode.role.add("section"); + + // child elements in seq + parseParameters(e, mediaOverlayNode, href); + node.children.add(mediaOverlayNode); + // recur to parse child node elements + parseSequences(e, mediaOverlayNode, publication, href); + + if (node.text == null) return; + + // Not clear about the IRI reference, epub:textref in seq may not have [ "#" ifragment ] + // ref:- https://www.idpf.org/epub/30/spec/epub30-mediaoverlays.html#sec-smil-seq-elem + // TODO is it req? code ref from https://github.com/readium/r2-streamer-swift/blob/feature/media-overlay/Sources/parser/SMILParser.swift + // can be done with contains? + + String baseHrefParent = node.text; + if (node.text.contains("#")) { + baseHrefParent = node.text.split("#")[0]; + } + if (mediaOverlayNode.text.contains("#")) { + String baseHref = mediaOverlayNode.text.split("#")[0]; + + if (!baseHref.equals(baseHrefParent)) { + int position = getPosition(publication.spines, baseHref); + + if (position != -1) + addMediaOverlayToSpine(publication, mediaOverlayNode, position); + } + } + } + } + } + } + + /** + * Parse the elements at the current XML element level. + * + * @param body input element with seq tag + * @param node contains parsed elements + */ + private static void parseParameters(Element body, MediaOverlayNode node, String href) { + NodeList par = body.getElementsByTagName("par"); + if (par.getLength() == 0) { + return; + } + // For each in the current scope. + for (Node n = body.getFirstChild(); n != null; n = n.getNextSibling()) { + if (n.getNodeType() == Node.ELEMENT_NODE) { + Element e = (Element) n; + if (e.getTagName().equalsIgnoreCase("par")) { + MediaOverlayNode mediaOverlayNode = new MediaOverlayNode(); + Element text = (Element) e.getElementsByTagName("text").item(0); + Element audio = (Element) e.getElementsByTagName("audio").item(0); + + if (text != null) mediaOverlayNode.text = text.getAttribute("src"); + if (audio != null) { + mediaOverlayNode.audio = SMILParser.parseAudio(audio, href); + } + node.children.add(mediaOverlayNode); + } + } + } + } + + /** + * Add parsed media-overlay object to corresponding spine item + * + * @param publication publication object + * @param node parsed media overlay node + * @param position position on spine item in publication + */ + private static void addMediaOverlayToSpine(EpubPublication publication, MediaOverlayNode node, int position) { + publication.spines.get(position).mediaOverlay.mediaOverlayNodes.add(node); + publication.spines.get(position).properties.add("media-overlay?resource=" + publication.spines.get(position).href); + + publication.links.add(new Link( + "port/media-overlay?resource=" + publication.spines.get(position).href, //replace the port with proper url in EpubServer#addLinks + "media-overlay", + "application/vnd.readium.mo+json")); + } + + /** + * returns position of the spine whose href equals baseHref + * + * @param spines spine list in publication + * @param baseHref name of the file which corresponding to media-overlay + * @return returns position of the spine item + */ + private static int getPosition(List spines, String baseHref) { + for (Link link : spines) { + int offset = link.href.indexOf("/", 0); + int startIndex = link.href.indexOf("/", offset + 1); + String path = link.href.substring(startIndex + 1); + if (baseHref.contains(path)) { + return spines.indexOf(link); + } + } + return -1; + } +}