This commit is contained in:
Sébastien Lucas 2012-05-28 07:06:12 +02:00
rodič f460bd8731
revize 2308af6033
10 změnil soubory, kde provedl 146 přidání a 24 odebrání

Zobrazit soubor

@ -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

Zobrazit soubor

@ -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
}
}
?>
?>

8
README
Zobrazit soubor

@ -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.

Zobrazit soubor

@ -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;
}

Zobrazit soubor

@ -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

Zobrazit soubor

@ -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;
}

Zobrazit soubor

@ -6,13 +6,15 @@
* @author Sébastien Lucas <sebastien@slucas.fr>
*/
$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";
?>

Zobrazit soubor

@ -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 ();

Zobrazit soubor

@ -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]);

Zobrazit soubor

@ -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;
}