X-Git-Url: https://git.rvb.name/openlib.git/blobdiff_plain/a47401f5fac121db5eb44214530121ab14cba2f3..6b3a07a008979ee27733a2deae2ff4fc42f4a535:/www/OPDS_renderer.php?ds=sidebyside diff --git a/www/OPDS_renderer.php b/www/OPDS_renderer.php new file mode 100644 index 0000000..10156ff --- /dev/null +++ b/www/OPDS_renderer.php @@ -0,0 +1,271 @@ + + */ + +require_once ("base.php"); + +class OPDSRenderer +{ + const PAGE_OPENSEARCH = "8"; + const PAGE_OPENSEARCH_QUERY = "9"; + + private $xmlStream = NULL; + private $updated = NULL; + + private function getUpdatedTime () { + if (is_null ($this->updated)) { + $this->updated = time(); + } + return date (DATE_ATOM, $this->updated); + } + + private function getXmlStream () { + if (is_null ($this->xmlStream)) { + $this->xmlStream = new XMLWriter(); + $this->xmlStream->openMemory(); + $this->xmlStream->setIndent (true); + } + return $this->xmlStream; + } + + public function getOpenSearch () { + global $config; + $xml = new XMLWriter (); + $xml->openMemory (); + $xml->setIndent (true); + $xml->startDocument('1.0','UTF-8'); + $xml->startElement ("OpenSearchDescription"); + $xml->writeAttribute ("xmlns", "http://a9.com/-/spec/opensearch/1.1/"); + $xml->startElement ("ShortName"); + $xml->text ("My catalog"); + $xml->endElement (); + $xml->startElement ("Description"); + $xml->text ("Search for ebooks"); + $xml->endElement (); + $xml->startElement ("InputEncoding"); + $xml->text ("UTF-8"); + $xml->endElement (); + $xml->startElement ("OutputEncoding"); + $xml->text ("UTF-8"); + $xml->endElement (); + $xml->startElement ("Image"); + $xml->writeAttribute ("type", "image/x-icon"); + $xml->writeAttribute ("width", "16"); + $xml->writeAttribute ("height", "16"); + $xml->text ($config['cops_icon']); + $xml->endElement (); + $xml->startElement ("Url"); + $xml->writeAttribute ("type", 'application/atom+xml'); + $urlparam = "?query={searchTerms}"; + if (!is_null (GetUrlParam (DB))) $urlparam = addURLParameter ($urlparam, DB, GetUrlParam (DB)); + $urlparam = str_replace ("%7B", "{", $urlparam); + $urlparam = str_replace ("%7D", "}", $urlparam); + $xml->writeAttribute ("template", $config['cops_full_url'] . 'feed.php' . $urlparam); + $xml->endElement (); + $xml->startElement ("Query"); + $xml->writeAttribute ("role", "example"); + $xml->writeAttribute ("searchTerms", "robot"); + $xml->endElement (); + $xml->endElement (); + $xml->endDocument(); + return $xml->outputMemory(true); + } + + private function startXmlDocument ($page) { + global $config; + self::getXmlStream ()->startDocument('1.0','UTF-8'); + self::getXmlStream ()->startElement ("feed"); + self::getXmlStream ()->writeAttribute ("xmlns", "http://www.w3.org/2005/Atom"); + self::getXmlStream ()->writeAttribute ("xmlns:xhtml", "http://www.w3.org/1999/xhtml"); + self::getXmlStream ()->writeAttribute ("xmlns:opds", "http://opds-spec.org/2010/catalog"); + self::getXmlStream ()->writeAttribute ("xmlns:opensearch", "http://a9.com/-/spec/opensearch/1.1/"); + self::getXmlStream ()->writeAttribute ("xmlns:dcterms", "http://purl.org/dc/terms/"); + self::getXmlStream ()->startElement ("title"); + self::getXmlStream ()->text ($page->title); + self::getXmlStream ()->endElement (); + if ($page->subtitle != "") + { + self::getXmlStream ()->startElement ("subtitle"); + self::getXmlStream ()->text ($page->subtitle); + self::getXmlStream ()->endElement (); + } + self::getXmlStream ()->startElement ("id"); + if ($page->idPage) + { + $idPage = $page->idPage; + if (!is_null (GetUrlParam (DB))) $idPage = str_replace ("cops:", "cops:" . GetUrlParam (DB) . ":", $idPage); + self::getXmlStream ()->text ($idPage); + } + else + { + self::getXmlStream ()->text ($_SERVER['REQUEST_URI']); + } + self::getXmlStream ()->endElement (); + self::getXmlStream ()->startElement ("updated"); + self::getXmlStream ()->text (self::getUpdatedTime ()); + self::getXmlStream ()->endElement (); + self::getXmlStream ()->startElement ("icon"); + self::getXmlStream ()->text ($page->favicon); + self::getXmlStream ()->endElement (); + self::getXmlStream ()->startElement ("author"); + self::getXmlStream ()->startElement ("name"); + self::getXmlStream ()->text ($page->authorName); + self::getXmlStream ()->endElement (); + self::getXmlStream ()->startElement ("uri"); + self::getXmlStream ()->text ($page->authorUri); + self::getXmlStream ()->endElement (); + self::getXmlStream ()->startElement ("email"); + self::getXmlStream ()->text ($page->authorEmail); + self::getXmlStream ()->endElement (); + self::getXmlStream ()->endElement (); + $link = new LinkNavigation ("", "start", "Home"); + self::renderLink ($link); + $link = new LinkNavigation ("?" . $_SERVER['QUERY_STRING'], "self"); + self::renderLink ($link); + $urlparam = "?"; + if (!is_null (GetUrlParam (DB))) $urlparam = addURLParameter ($urlparam, DB, GetUrlParam (DB)); + if ($config['cops_generate_invalid_opds_stream'] == 0 || preg_match("/(MantanoReader|FBReader)/", $_SERVER['HTTP_USER_AGENT'])) { + // Good and compliant way of handling search + $urlparam = addURLParameter ($urlparam, "page", self::PAGE_OPENSEARCH); + $link = new Link ("feed.php" . $urlparam, "application/opensearchdescription+xml", "search", "Search here"); + } + else + { + // Bad way, will be removed when OPDS client are fixed + $urlparam = addURLParameter ($urlparam, "query", "{searchTerms}"); + $urlparam = str_replace ("%7B", "{", $urlparam); + $urlparam = str_replace ("%7D", "}", $urlparam); + $link = new Link ($config['cops_full_url'] . 'feed.php' . $urlparam, "application/atom+xml", "search", "Search here"); + } + self::renderLink ($link); + if ($page->containsBook () && !is_null ($config['cops_books_filter']) && count ($config['cops_books_filter']) > 0) { + $Urlfilter = getURLParam ("tag", ""); + foreach ($config['cops_books_filter'] as $lib => $filter) { + $link = new LinkFacet ("?" . addURLParameter ($_SERVER['QUERY_STRING'], "tag", $filter), $lib, localize ("tagword.title"), $filter == $Urlfilter); + self::renderLink ($link); + } + } + } + + private function endXmlDocument () { + self::getXmlStream ()->endElement (); + self::getXmlStream ()->endDocument (); + return self::getXmlStream ()->outputMemory(true); + } + + private function renderLink ($link) { + self::getXmlStream ()->startElement ("link"); + self::getXmlStream ()->writeAttribute ("href", $link->href); + self::getXmlStream ()->writeAttribute ("type", $link->type); + if (!is_null ($link->rel)) { + self::getXmlStream ()->writeAttribute ("rel", $link->rel); + } + if (!is_null ($link->title)) { + self::getXmlStream ()->writeAttribute ("title", $link->title); + } + if (!is_null ($link->facetGroup)) { + self::getXmlStream ()->writeAttribute ("opds:facetGroup", $link->facetGroup); + } + if ($link->activeFacet) { + self::getXmlStream ()->writeAttribute ("opds:activeFacet", "true"); + } + self::getXmlStream ()->endElement (); + } + + + private function renderEntry ($entry) { + self::getXmlStream ()->startElement ("title"); + self::getXmlStream ()->text ($entry->title); + self::getXmlStream ()->endElement (); + self::getXmlStream ()->startElement ("updated"); + self::getXmlStream ()->text (self::getUpdatedTime ()); + self::getXmlStream ()->endElement (); + self::getXmlStream ()->startElement ("id"); + self::getXmlStream ()->text ($entry->id); + self::getXmlStream ()->endElement (); + self::getXmlStream ()->startElement ("content"); + self::getXmlStream ()->writeAttribute ("type", $entry->contentType); + if ($entry->contentType == "text") { + self::getXmlStream ()->text ($entry->content); + } else { + self::getXmlStream ()->writeRaw ($entry->content); + } + self::getXmlStream ()->endElement (); + foreach ($entry->linkArray as $link) { + self::renderLink ($link); + } + + if (get_class ($entry) != "EntryBook") { + return; + } + + foreach ($entry->book->getAuthors () as $author) { + self::getXmlStream ()->startElement ("author"); + self::getXmlStream ()->startElement ("name"); + self::getXmlStream ()->text ($author->name); + self::getXmlStream ()->endElement (); + self::getXmlStream ()->startElement ("uri"); + self::getXmlStream ()->text ("feed.php" . $author->getUri ()); + self::getXmlStream ()->endElement (); + self::getXmlStream ()->endElement (); + } + foreach ($entry->book->getTags () as $category) { + self::getXmlStream ()->startElement ("category"); + self::getXmlStream ()->writeAttribute ("term", $category->name); + self::getXmlStream ()->writeAttribute ("label", $category->name); + self::getXmlStream ()->endElement (); + } + if ($entry->book->getPubDate () != "") { + self::getXmlStream ()->startElement ("dcterms:issued"); + self::getXmlStream ()->text (date ("Y-m-d", $entry->book->pubdate)); + self::getXmlStream ()->endElement (); + self::getXmlStream ()->startElement ("published"); + self::getXmlStream ()->text (date ("Y-m-d", $entry->book->pubdate) . "T08:08:08Z"); + self::getXmlStream ()->endElement (); + } + + $lang = $entry->book->getLanguages (); + if (!empty ($lang)) { + self::getXmlStream ()->startElement ("dcterms:language"); + self::getXmlStream ()->text ($lang); + self::getXmlStream ()->endElement (); + } + + } + + public function render ($page) { + global $config; + self::startXmlDocument ($page); + if ($page->isPaginated ()) + { + self::getXmlStream ()->startElement ("opensearch:totalResults"); + self::getXmlStream ()->text ($page->totalNumber); + self::getXmlStream ()->endElement (); + self::getXmlStream ()->startElement ("opensearch:itemsPerPage"); + self::getXmlStream ()->text ($config['cops_max_item_per_page']); + self::getXmlStream ()->endElement (); + self::getXmlStream ()->startElement ("opensearch:startIndex"); + self::getXmlStream ()->text (($page->n - 1) * $config['cops_max_item_per_page'] + 1); + self::getXmlStream ()->endElement (); + $prevLink = $page->getPrevLink (); + $nextLink = $page->getNextLink (); + if (!is_null ($prevLink)) { + self::renderLink ($prevLink); + } + if (!is_null ($nextLink)) { + self::renderLink ($nextLink); + } + } + foreach ($page->entryArray as $entry) { + self::getXmlStream ()->startElement ("entry"); + self::renderEntry ($entry); + self::getXmlStream ()->endElement (); + } + return self::endXmlDocument (); + } +} +