このコミットが含まれているのは:
Sébastien Lucas 2012-05-28 07:06:12 +02:00
コミット 2308af6033
10個のファイルの変更146行の追加24行の削除

ファイルの表示

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

ファイルの表示

@ -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
ファイルの表示

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

ファイルの表示

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

ファイルの表示

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

ファイルの表示

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

ファイルの表示

@ -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";
?>

ファイルの表示

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

ファイルの表示

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

ファイルの表示

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