diff --git a/CHANGELOG b/CHANGELOG index 0ab6524..b0f6ffe 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,8 +1,17 @@ +0.0.3 - 20120507 + * Fixed many things blocking opensearch from working + * There was a bug introduced in 0.0.2 + * The URL can't be relative for Mantano reader, so I added a configuration item. + * I continued the refactoring to bring HTML to COPS + * Thumbnails have bigger size (I'll add a configuration item later) + * Add headers to help caching image and thumbnail to the browser + * + 0.0.2 - 20120411 - * Add support for MOBI and PDF - * Major refactoring to prepare something nice for the future ;) - * Add a config item to make use of X-Sendfile instead of X-Accel-Redirect - if needed + * Add support for MOBI and PDF + * Major refactoring to prepare something nice for the future ;) + * Add a config item to make use of X-Sendfile instead of X-Accel-Redirect if needed 0.0.1 - 20120302 - * First public release + * First public release + \ No newline at end of file diff --git a/OPDS_renderer.php b/OPDS_renderer.php index da082e5..1657308 100644 --- a/OPDS_renderer.php +++ b/OPDS_renderer.php @@ -11,6 +11,7 @@ require_once ("base.php"); class OPDSRenderer { const PAGE_OPENSEARCH = "8"; + const PAGE_OPENSEARCH_QUERY = "9"; private $xmlStream = NULL; private $updated = NULL; @@ -32,11 +33,13 @@ class OPDSRenderer } 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 (); @@ -47,11 +50,18 @@ class OPDSRenderer $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 ("favicon.ico"); $xml->endElement (); $xml->startElement ("Url"); $xml->writeAttribute ("type", 'application/atom+xml'); - $xml->writeAttribute ("template", 'feed.php?page=' . self::PAGE_OPENSEARCH_QUERY . '&query={searchTerms}'); + $xml->writeAttribute ("template", $config['cops_full_url'] . 'feed.php?query={searchTerms}'); + $xml->endElement (); + $xml->startElement ("Query"); + $xml->writeAttribute ("role", "example"); + $xml->writeAttribute ("searchTerms", "robot"); $xml->endElement (); $xml->endElement (); $xml->endDocument(); @@ -89,9 +99,9 @@ class OPDSRenderer self::getXmlStream ()->text ("sebastien@slucas.fr"); self::getXmlStream ()->endElement (); self::getXmlStream ()->endElement (); - $link = new LinkNavigation ("feed.php", "start", "Home"); + $link = new LinkNavigation ("", "start", "Home"); self::renderLink ($link); - $link = new LinkNavigation ($_SERVER['REQUEST_URI'], "self"); + $link = new LinkNavigation ("?" . $_SERVER['QUERY_STRING'], "self"); self::renderLink ($link); $link = new Link ("feed.php?page=" . self::PAGE_OPENSEARCH, "application/opensearchdescription+xml", "search", "Search here"); self::renderLink ($link); @@ -169,6 +179,18 @@ class OPDSRenderer public function render ($page) { self::startXmlDocument ($page->title); + if ($page->query) + { + self::getXmlStream ()->startElement ("opensearch:totalResults"); + self::getXmlStream ()->text (count($page->entryArray)); + self::getXmlStream ()->endElement (); + self::getXmlStream ()->startElement ("opensearch:itemsPerPage"); + self::getXmlStream ()->text (count($page->entryArray)); + self::getXmlStream ()->endElement (); + self::getXmlStream ()->startElement ("opensearch:startIndex"); + self::getXmlStream ()->text ("1"); + self::getXmlStream ()->endElement (); + } foreach ($page->entryArray as $entry) { self::getXmlStream ()->startElement ("entry"); self::renderEntry ($entry); @@ -178,4 +200,4 @@ class OPDSRenderer } } -?> \ No newline at end of file +?> diff --git a/README b/README index 7571ce6..bbe7bbb 100644 --- a/README +++ b/README @@ -74,6 +74,14 @@ If you choose to put your Calibre directory inside your web directory then you will have to edit /etc/nginx/mime.types to add this line : application/epub+zip epub; += Notes on Opensearch = + +Opensearch allow searching through an OPDS catalog. After many tests, I've been +able to make it work with FBReader and Mantano Reader. + +It seems that Aldiko didn't implement it properly so it won't work with COPS or +any other custom OPDS catalog. + = Known problems = * Only tested with Nginx. diff --git a/author.php b/author.php index e8aa0bb..3727a8e 100644 --- a/author.php +++ b/author.php @@ -21,7 +21,7 @@ class Author extends Base { } public function getUri () { - return "feed.php?page=".parent::PAGE_AUTHOR_DETAIL."&id=$this->id"; + return "?page=".parent::PAGE_AUTHOR_DETAIL."&id=$this->id"; } public function getEntryId () { @@ -33,7 +33,7 @@ class Author extends Base { $nAuthors = parent::getDb ()->query('select count(*) from authors')->fetchColumn(); $entry = new Entry ("Authors", self::ALL_AUTHORS_ID, "Alphabetical index of the $nAuthors authors", "text", - array ( new LinkNavigation ("feed.php?page=".parent::PAGE_ALL_AUTHORS))); + array ( new LinkNavigation ("?page=".parent::PAGE_ALL_AUTHORS))); return $entry; } diff --git a/base.php b/base.php index 8c305bf..878967a 100644 --- a/base.php +++ b/base.php @@ -26,6 +26,10 @@ class Link $this->rel = $prel; $this->title = $ptitle; } + + public function hrefXhtml () { + return str_replace ("&", "&", $this->href); + } } class LinkNavigation extends Link @@ -34,6 +38,7 @@ class LinkNavigation extends Link public function __construct($phref, $prel = NULL, $ptitle = NULL) { parent::__construct ($phref, self::OPDS_NAVIGATION_TYPE, $prel, $ptitle); + $this->href = $_SERVER["SCRIPT_NAME"] . $this->href; } } @@ -76,6 +81,14 @@ class EntryBook extends Entry $this->book = $pbook; $this->localUpdated = $pbook->timestamp; } + + public function getCoverThumbnail () { + foreach ($this->linkArray as $link) { + if ($link->rel == "http://opds-spec.org/image/thumbnail") + return $link->hrefXhtml (); + } + return null; + } } class Page diff --git a/book.php b/book.php index 493ea42..808f11f 100644 --- a/book.php +++ b/book.php @@ -25,6 +25,7 @@ class Book extends Base { public $authors = NULL; public $serie = NULL; public $tags = NULL; + public $format = array (); public static $mimetypes = array( 'epub' => 'application/epub+zip', 'mobi' => 'application/x-mobipocket-ebook', @@ -59,6 +60,20 @@ class Book extends Base { return $this->authors; } + public function getAuthorsName () { + $authorList = null; + foreach ($this->getAuthors () as $author) { + if ($authorList) { + $authorList = $authorList . ", " . $author->name; + } + else + { + $authorList = $author->name; + } + } + return $authorList; + } + public function getSerie () { if (is_null ($this->serie)) { $this->serie = Serie::getSerieByBookId ($this->id); @@ -84,6 +99,20 @@ class Book extends Base { return $this->tags; } + public function getTagsName () { + $tagList = null; + foreach ($this->getTags () as $tag) { + if ($tagList) { + $tagList = $tagList . ", " . $tag; + } + else + { + $tagList = $tag; + } + } + return $tagList; + } + public function getComment () { $addition = ""; $se = $this->getSerie (); @@ -125,20 +154,21 @@ class Book extends Base { } else { - array_push ($linkArray, new Link (rawurlencode ($this->path."/".$file), "image/jpeg", "http://opds-spec.org/image")); + array_push ($linkArray, new Link (str_replace('%2F','/',rawurlencode ($this->path."/".$file)), "image/jpeg", "http://opds-spec.org/image")); } - array_push ($linkArray, new Link ("fetch.php?id=$this->id&width=50", "image/jpeg", "http://opds-spec.org/image/thumbnail")); + array_push ($linkArray, new Link ("fetch.php?id=$this->id&height=70", "image/jpeg", "http://opds-spec.org/image/thumbnail")); } foreach (self::$mimetypes as $ext => $mime) { if (preg_match ('/'. $ext .'$/', $file)) { + $this->format [$ext] = $file; if (preg_match ('/^\//', $config['calibre_directory'])) { array_push ($linkArray, new Link ("fetch.php?id=$this->id&type=" . $ext, $mime, "http://opds-spec.org/acquisition", "Download")); } else { - array_push ($linkArray, new Link (rawurlencode ($this->path."/".$file), $mime, "http://opds-spec.org/acquisition", "Download")); + array_push ($linkArray, new Link (str_replace('%2F','/',rawurlencode ($this->path."/".$file)), $mime, "http://opds-spec.org/acquisition", "Download")); } } } @@ -171,12 +201,12 @@ class Book extends Base { $entry = new Entry ("Books", self::ALL_BOOKS_ID, "Alphabetical index of the $nBooks books", "text", - array ( new LinkNavigation ("feed.php?page=".parent::PAGE_ALL_BOOKS))); + array ( new LinkNavigation ("?page=".parent::PAGE_ALL_BOOKS))); array_push ($result, $entry); $entry = new Entry ("Recents books", self::ALL_RECENT_BOOKS_ID, "Alphabetical index of the " . $config['cops_recentbooks_limit'] . " most recent books", "text", - array ( new LinkNavigation ("feed.php?page=".parent::PAGE_ALL_RECENT_BOOKS))); + array ( new LinkNavigation ("?page=".parent::PAGE_ALL_RECENT_BOOKS))); array_push ($result, $entry); return $result; } @@ -253,7 +283,7 @@ order by substr (upper (sort), 1, 1)"); { array_push ($entryArray, new Entry ($post->title, "allbooks_" . $post->title, "$post->count books", "text", - array ( new LinkNavigation ("feed.php?page=".parent::PAGE_ALL_BOOKS_LETTER."&id=".$post->title)))); + array ( new LinkNavigation ("?page=".parent::PAGE_ALL_BOOKS_LETTER."&id=".$post->title)))); } return $entryArray; } diff --git a/config_default.php b/config_default.php index 75e3359..88f762a 100644 --- a/config_default.php +++ b/config_default.php @@ -6,13 +6,15 @@ * @author Sébastien Lucas */ - $config = array(); + if (!isset($config)) + $config = array(); /* * The directory containing calibre's metadata.db file, with sub-directories * containing all the formats. * If this directory starts with a / EPUB download will only work with Nginx - * and if the calibre_internal_directory is set + * and the calibre_internal_directory has to be set properly + * BEWARE : it has to end with a / */ $config['calibre_directory'] = './'; @@ -23,7 +25,14 @@ $config['calibre_internal_directory'] = '/Calibre/'; /* - * Number of books + * Full URL prefix (with trailing /) + * usefull especially for Opensearch where a full URL is sometimes required + * For example Mantano requires it. + */ + $config['cops_full_url'] = ''; + + /* + * Number of recent books to show */ $config['cops_recentbooks_limit'] = '50'; @@ -39,5 +48,5 @@ * X-Accel-Redirect : For Nginx * X-Sendfile : For Lightttpd or Apache (with mod_xsendfile) */ - $config['cops_x_accel_redirect'] = "X-Accel-Redirect"; + $config['cops_x_accel_redirect'] = "X-Accel-Redirect"; ?> \ No newline at end of file diff --git a/feed.php b/feed.php index 68fd48b..f2348c7 100644 --- a/feed.php +++ b/feed.php @@ -17,6 +17,8 @@ header ("Content-Type:application/xml"); $page = getURLParam ("page", Base::PAGE_INDEX); $query = getURLParam ("query"); + if ($query) + $page = Base::PAGE_OPENSEARCH_QUERY; $qid = getURLParam ("id"); $OPDSRender = new OPDSRenderer (); diff --git a/fetch.php b/fetch.php index fbd79ea..b81be61 100644 --- a/fetch.php +++ b/fetch.php @@ -10,6 +10,10 @@ require_once ("book.php"); global $config; + $expires = 60*60*24*14; + header("Pragma: public"); + header("Cache-Control: maxage=".$expires); + header('Expires: ' . gmdate('D, d M Y H:i:s', time()+$expires) . ' GMT'); $bookId = $_GET["id"]; $book = Book::getBookById($bookId); $type = getURLParam ("type", "jpg"); @@ -43,6 +47,31 @@ imagedestroy($dst_img); return; } + if (isset($_GET["height"])) + { + $file = $book->getFilePath ($type); + // get image size + if($size = GetImageSize($file)){ + $w = $size[0]; + $h = $size[1]; + //set new size + $nh = $_GET["height"]; + $nw = ($nh*$w)/$h; + } + else{ + //set new size + $nw = "160"; + $nh = "120"; + } + //draw the image + $src_img = imagecreatefromjpeg($file); + $dst_img = imagecreatetruecolor($nw,$nh); + imagecopyresampled($dst_img, $src_img, 0, 0, 0, 0, $nw, $nh, $w, $h);//resizing the image + imagejpeg($dst_img,"",100); + imagedestroy($src_img); + imagedestroy($dst_img); + return; + } break; default: header("Content-type: " . Book::$mimetypes[$type]); diff --git a/serie.php b/serie.php index c269b3e..be03a91 100644 --- a/serie.php +++ b/serie.php @@ -20,14 +20,14 @@ class Serie extends Base { } public function getUri () { - return "feed.php?page=".parent::PAGE_SERIE_DETAIL."&id=$this->id"; + return "?page=".parent::PAGE_SERIE_DETAIL."&id=$this->id"; } public static function getCount() { $nSeries = parent::getDb ()->query('select count(*) from series')->fetchColumn(); $entry = new Entry ("Series", self::ALL_SERIES_ID, "Alphabetical index of the $nSeries series", "text", - array ( new LinkNavigation ("feed.php?page=".parent::PAGE_ALL_SERIES))); + array ( new LinkNavigation ("?page=".parent::PAGE_ALL_SERIES))); return $entry; } @@ -62,7 +62,7 @@ order by series.sort'); { array_push ($entryArray, new Entry ($post->sort, self::ALL_SERIES_ID.":".$post->id, "$post->count books", "text", - array ( new LinkNavigation ("feed.php?page=".parent::PAGE_SERIE_DETAIL."&id=$post->id")))); + array ( new LinkNavigation ("?page=".parent::PAGE_SERIE_DETAIL."&id=$post->id")))); } return $entryArray; }