Merge almost everything. a lot to test.

This commit is contained in:
Sébastien Lucas 2013-05-15 21:55:33 +02:00
commit 639d1bf8b0
45 changed files with 800 additions and 338 deletions

View file

@ -11,3 +11,6 @@ c5703623704b81dca4228e211830125029cf86a1 0.2.3
5cc3b8ed121d9df57e013e050a75e5602cf2198e 0.3.0 5cc3b8ed121d9df57e013e050a75e5602cf2198e 0.3.0
aca483636af460c93f9817e083e85d1976aa1b7d 0.3.1 aca483636af460c93f9817e083e85d1976aa1b7d 0.3.1
5888006bc559842de0364ec3e67f641aa1653d0e 0.3.2 5888006bc559842de0364ec3e67f641aa1653d0e 0.3.2
2ff58ed42cecf00b24d981426dff507fa1e86c20 0.3.3
3cdee8daedf28e6611203ce90c90bb8906003e22 0.3.4
89ed9654ac9c5de1695f63992aa92d55ef82f2b9 0.4.0

View file

@ -19,8 +19,10 @@
<IfModule mod_rewrite.c> <IfModule mod_rewrite.c>
RewriteEngine on RewriteEngine on
RewriteRule ^download/(.*)/.*\.kepub\.epub$ fetch.php?data=$1&type=epub [L] RewriteRule ^download/(\d*)/(\d*)/.*\.kepub\.epub$ fetch.php?data=$1&db=$2&type=epub [L]
RewriteRule ^download/(.*)/.*\.(.*)$ fetch.php?data=$1&type=$2 [L] RewriteRule ^download/(\d*)/(\d*)/.*\.(.*)$ fetch.php?data=$1&db=$2&type=$3 [L]
RewriteRule ^download/(\d*)/.*\.kepub\.epub$ fetch.php?data=$1&type=epub [L]
RewriteRule ^download/(\d*)/.*\.(.*)$ fetch.php?data=$1&type=$2 [L]
</IfModule> </IfModule>
########################################### ###########################################

View file

@ -1,3 +1,26 @@
0.4.0 - 20130507
* Add multiple database support. Check the documentation of $config['calibre_directory'] in config-default.php to see how ot enable it.
* Include jquery library in COPS's repository to be sure that COPS will work on LAN (without Internet access).
* Prepare the switch to HTML5. Thanks to Thomas Severinsen for most of the code.
* Update the locale strings to be more strict with plurals. Thanks to Tobias Ausländer for the code.
* If Fancybox is not enabled ($config['cops_use_fancyapps'] = "0") then it's not used at all (even in the about box).
* Fix book comments if it contains UTF8 characters. Reported by Alain.
* Link to the book permalink was not working correctly in some cases. Reported by celta.
* Moved some external resources to a resources directory.
* Add chinese translation. Thanks to wogong for the pull request.
0.3.4 - 20130327
* Hopefully fix metadata update. Beware you should remove the directory php-epub-meta if you have one. Thanks to Mario for his time.
* Fix two warnings. Reported by Goner and Mario.
0.3.3 - 20130323
* Fix catalog if book summary contains bad HTML again :(.
* Upgrade to Fancybox 2.4.0 and JQuery 1.9.1.
* Search is now dependant on the page you're in. For now if you're on author page it'll look for author name.
* Update checkconfig to check if the database provided comes from Calibre.
* Update to latest php-epub-meta should fix the metadata update with Epub.
* Fix OPDS catalog with Ibis Reader. It didn't like empty language.
0.3.2 - 20130303 0.3.2 - 20130303
* Add dutch translation. Provided by Northguy. * Add dutch translation. Provided by Northguy.
* Fix an ugly bug introduced in 0.3.1. Reported by mariosipad. * Fix an ugly bug introduced in 0.3.1. Reported by mariosipad.

View file

@ -60,7 +60,11 @@ class OPDSRenderer
$xml->endElement (); $xml->endElement ();
$xml->startElement ("Url"); $xml->startElement ("Url");
$xml->writeAttribute ("type", 'application/atom+xml'); $xml->writeAttribute ("type", 'application/atom+xml');
$xml->writeAttribute ("template", $config['cops_full_url'] . 'feed.php?query={searchTerms}'); $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->endElement ();
$xml->startElement ("Query"); $xml->startElement ("Query");
$xml->writeAttribute ("role", "example"); $xml->writeAttribute ("role", "example");
@ -92,7 +96,9 @@ class OPDSRenderer
self::getXmlStream ()->startElement ("id"); self::getXmlStream ()->startElement ("id");
if ($page->idPage) if ($page->idPage)
{ {
self::getXmlStream ()->text ($page->idPage); $idPage = $page->idPage;
if (!is_null (GetUrlParam (DB))) $idPage = GetUrlParam (DB) . ":" . $idPage;
self::getXmlStream ()->text ($idPage);
} }
else else
{ {
@ -120,14 +126,16 @@ class OPDSRenderer
self::renderLink ($link); self::renderLink ($link);
$link = new LinkNavigation ("?" . $_SERVER['QUERY_STRING'], "self"); $link = new LinkNavigation ("?" . $_SERVER['QUERY_STRING'], "self");
self::renderLink ($link); self::renderLink ($link);
$urlparam = "?page=" . self::PAGE_OPENSEARCH;
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'])) { if ($config['cops_generate_invalid_opds_stream'] == 0 || preg_match("/(MantanoReader|FBReader)/", $_SERVER['HTTP_USER_AGENT'])) {
// Good and compliant way of handling search // Good and compliant way of handling search
$link = new Link ("feed.php?page=" . self::PAGE_OPENSEARCH, "application/opensearchdescription+xml", "search", "Search here"); $link = new Link ("feed.php" . $urlparam, "application/opensearchdescription+xml", "search", "Search here");
} }
else else
{ {
// Bad way, will be removed when OPDS client are fixed // Bad way, will be removed when OPDS client are fixed
$link = new Link ($config['cops_full_url'] . 'feed.php?query={searchTerms}', "application/atom+xml", "search", "Search here"); $link = new Link ($config['cops_full_url'] . 'feed.php' . $urlparam, "application/atom+xml", "search", "Search here");
} }
self::renderLink ($link); self::renderLink ($link);
if ($page->containsBook () && !is_null ($config['cops_books_filter']) && count ($config['cops_books_filter']) > 0) { if ($page->containsBook () && !is_null ($config['cops_books_filter']) && count ($config['cops_books_filter']) > 0) {
@ -217,7 +225,7 @@ class OPDSRenderer
} }
$lang = $entry->book->getLanguages (); $lang = $entry->book->getLanguages ();
if (!is_null ($lang)) { if (!empty ($lang)) {
self::getXmlStream ()->startElement ("dcterms:language"); self::getXmlStream ()->startElement ("dcterms:language");
self::getXmlStream ()->text ($lang); self::getXmlStream ()->text ($lang);
self::getXmlStream ()->endElement (); self::getXmlStream ()->endElement ();

29
about.xml Normal file
View file

@ -0,0 +1,29 @@
<div class="bookdetail">
<div class="entryTitle">Authors</div>
<div class="content" style="max-width:700px;">
<p>COPS is developped and maintained by Sébastien Lucas.</p>
<p>See full history on <a href="https://github.com/seblucas">Github</a> to check all authors.</p>
<p>COPS use some external librairies, check README for the details.</p>
</div>
<div class="entryTitle">Copyright</div>
<div class="content" style="max-width:700px;">
<p>This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation.</p>
<p>The complete content of license is provided in file COPYING within distribution and also available <a href="http://www.gnu.org/licenses/gpl-2.0.html">online</a>.</p>
</div>
<div class="entryTitle">Contact</div>
<div class="content" style="max-width:700px;">
<p>For more info please visit <a href="http://blog.slucas.fr/en/oss/calibre-opds-php-server">COPS Home Page</a></p>
<p>You can also check <a href="http://www.mobileread.com/forums/showthread.php?t=170903">COPS's topic on MobileRead forum</a>.</p>
</div>
<div class="entryTitle">Thanks</div>
<div class="content" style="max-width:700px;">
<p>Thanks a lot to Kovid Goyal for <a href="http://calibre-ebook.com">Calibre</a>.</p>
<p>And many thanks to all those who helped test COPS.</p>
</div>
</div>

View file

@ -39,7 +39,7 @@ class Author extends Base {
public static function getCount() { public static function getCount() {
$nAuthors = parent::getDb ()->query('select count(*) from authors')->fetchColumn(); $nAuthors = parent::getDb ()->query('select count(*) from authors')->fetchColumn();
$entry = new Entry (localize("authors.title"), self::ALL_AUTHORS_ID, $entry = new Entry (localize("authors.title"), self::ALL_AUTHORS_ID,
str_format (localize("authors.alphabetical"), $nAuthors), "text", str_format (localize("authors.alphabetical", $nAuthors), $nAuthors), "text",
array ( new LinkNavigation ("?page=".parent::PAGE_ALL_AUTHORS))); array ( new LinkNavigation ("?page=".parent::PAGE_ALL_AUTHORS)));
return $entry; return $entry;
} }

201
base.php
View file

@ -6,7 +6,8 @@
* @author Sébastien Lucas <sebastien@slucas.fr> * @author Sébastien Lucas <sebastien@slucas.fr>
*/ */
define ("VERSION", "0.3.2"); define ("VERSION", "0.4.0");
define ("DB", "db");
date_default_timezone_set($config['default_timezone']); date_default_timezone_set($config['default_timezone']);
function getURLParam ($name, $default = NULL) { function getURLParam ($name, $default = NULL) {
@ -27,14 +28,66 @@ function xml2xhtml($xml) {
'), $xml); '), $xml);
} }
function display_xml_error($error)
{
$return .= str_repeat('-', $error->column) . "^\n";
switch ($error->level) {
case LIBXML_ERR_WARNING:
$return .= "Warning $error->code: ";
break;
case LIBXML_ERR_ERROR:
$return .= "Error $error->code: ";
break;
case LIBXML_ERR_FATAL:
$return .= "Fatal Error $error->code: ";
break;
}
$return .= trim($error->message) .
"\n Line: $error->line" .
"\n Column: $error->column";
if ($error->file) {
$return .= "\n File: $error->file";
}
return "$return\n\n--------------------------------------------\n\n";
}
function are_libxml_errors_ok ()
{
$errors = libxml_get_errors();
foreach ($errors as $error) {
if ($error->code == 801) return false;
}
return true;
}
function html2xhtml ($html) { function html2xhtml ($html) {
$doc = new DOMDocument(); $doc = new DOMDocument();
$doc->loadHTML($html); // Load the HTML libxml_use_internal_errors(true);
$output = utf8_decode($doc->saveXML($doc->documentElement)); // Transform to an Ansi xml stream
$output = xml2xhtml($output); // Fix the br / hr ... $doc->loadHTML('<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body>' .
if (preg_match ("/<html><body>(.*)<\/body><\/html>/", $output, $matches)) { $html . '</body></html>'); // Load the HTML
$output = $doc->saveXML($doc->documentElement); // Transform to an Ansi xml stream
$output = xml2xhtml($output);
if (preg_match ('#<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></meta></head><body>(.*)</body></html>#ms', $output, $matches)) {
$output = $matches [1]; // Remove <html><body> $output = $matches [1]; // Remove <html><body>
} }
/*
// In case of error with summary, use it to debug
$errors = libxml_get_errors();
foreach ($errors as $error) {
$output .= display_xml_error($error);
}
*/
if (!are_libxml_errors_ok ()) $output = "HTML code not valid.";
libxml_use_internal_errors(false);
return $output; return $output;
} }
@ -100,14 +153,19 @@ function localize($phrase, $count=-1) {
} }
function addURLParameter($urlParams, $paramName, $paramValue) { function addURLParameter($urlParams, $paramName, $paramValue) {
$start = "";
if (preg_match ("#^\?(.*)#", $urlParams, $matches)) {
$start = "?";
$urlParams = $matches[1];
}
$params = array(); $params = array();
parse_str($urlParams, $params); parse_str($urlParams, $params);
if (empty ($paramValue)) { if (empty ($paramValue) && $paramValue != 0) {
unset ($params[$paramName]); unset ($params[$paramName]);
} else { } else {
$params[$paramName] = $paramValue; $params[$paramName] = $paramValue;
} }
return http_build_query($params); return $start . http_build_query($params);
} }
class Link class Link
@ -143,7 +201,13 @@ class LinkNavigation extends Link
{ {
public function __construct($phref, $prel = NULL, $ptitle = NULL) { public function __construct($phref, $prel = NULL, $ptitle = NULL) {
parent::__construct ($phref, Link::OPDS_NAVIGATION_TYPE, $prel, $ptitle); parent::__construct ($phref, Link::OPDS_NAVIGATION_TYPE, $prel, $ptitle);
$this->href = $_SERVER["SCRIPT_NAME"] . $this->href; if (!is_null (GetUrlParam (DB))) $this->href = addURLParameter ($this->href, DB, GetUrlParam (DB));
if (!preg_match ("#^\?(.*)#", $this->href) && !empty ($this->href)) $this->href = "?" . $this->href;
if (preg_match ("/bookdetail.php/", $_SERVER["SCRIPT_NAME"])) {
$this->href = "index.php" . $this->href;
} else {
$this->href = $_SERVER["SCRIPT_NAME"] . $this->href;
}
} }
} }
@ -151,6 +215,7 @@ class LinkFacet extends Link
{ {
public function __construct($phref, $ptitle = NULL, $pfacetGroup = NULL, $pactiveFacet = FALSE) { public function __construct($phref, $ptitle = NULL, $pfacetGroup = NULL, $pactiveFacet = FALSE) {
parent::__construct ($phref, Link::OPDS_PAGING_TYPE, "http://opds-spec.org/facet", $ptitle, $pfacetGroup, $pactiveFacet); parent::__construct ($phref, Link::OPDS_PAGING_TYPE, "http://opds-spec.org/facet", $ptitle, $pfacetGroup, $pactiveFacet);
if (!is_null (GetUrlParam (DB))) $this->href = addURLParameter ($this->href, DB, GetUrlParam (DB));
$this->href = $_SERVER["SCRIPT_NAME"] . $this->href; $this->href = $_SERVER["SCRIPT_NAME"] . $this->href;
} }
} }
@ -203,6 +268,8 @@ class Entry
} }
} }
} }
if (!is_null (GetUrlParam (DB))) $this->id = GetUrlParam (DB) . ":" . $this->id;
} }
} }
@ -276,6 +343,8 @@ class Page
return new PageQueryResult ($id, $query, $n); return new PageQueryResult ($id, $query, $n);
case Base::PAGE_BOOK_DETAIL : case Base::PAGE_BOOK_DETAIL :
return new PageBookDetail ($id, $query, $n); return new PageBookDetail ($id, $query, $n);
case Base::PAGE_ABOUT :
return new PageAbout ($id, $query, $n);
default: default:
$page = new Page ($id, $query, $n); $page = new Page ($id, $query, $n);
$page->idPage = "cops:catalog"; $page->idPage = "cops:catalog";
@ -297,16 +366,29 @@ class Page
global $config; global $config;
$this->title = $config['cops_title_default']; $this->title = $config['cops_title_default'];
$this->subtitle = $config['cops_subtitle_default']; $this->subtitle = $config['cops_subtitle_default'];
array_push ($this->entryArray, Author::getCount()); $database = GetUrlParam (DB);
array_push ($this->entryArray, Serie::getCount()); if (is_array ($config['calibre_directory']) && is_null ($database)) {
array_push ($this->entryArray, Tag::getCount()); $i = 0;
foreach ($config['cops_calibre_custom_column'] as $lookup) { foreach ($config['calibre_directory'] as $key => $value) {
$customId = CustomColumn::getCustomId ($lookup); array_push ($this->entryArray, new Entry ($key, "{$i}:cops:catalog",
if (!is_null ($customId)) { "", "text",
array_push ($this->entryArray, CustomColumn::getCount($customId)); array ( new LinkNavigation ("?" . DB . "={$i}"))));
$i++;
} }
} else {
array_push ($this->entryArray, Author::getCount());
array_push ($this->entryArray, Serie::getCount());
array_push ($this->entryArray, Tag::getCount());
foreach ($config['cops_calibre_custom_column'] as $lookup) {
$customId = CustomColumn::getCustomId ($lookup);
if (!is_null ($customId)) {
array_push ($this->entryArray, CustomColumn::getCount($customId));
}
}
$this->entryArray = array_merge ($this->entryArray, Book::getCount());
if (!is_null ($database)) $this->title = Base::getDbName ();
} }
$this->entryArray = array_merge ($this->entryArray, Book::getCount());
} }
public function isPaginated () public function isPaginated ()
@ -498,8 +580,32 @@ class PageQueryResult extends Page
{ {
public function InitializeContent () public function InitializeContent ()
{ {
$this->title = "Search result for query *" . $this->query . "*"; // TODO I18N global $config;
list ($this->entryArray, $this->totalNumber) = Book::getBooksByQuery ($this->query, $this->n); $this->title = str_format (localize ("search.result"), $this->query);
$currentPage = getURLParam ("current", NULL);
// Special case when we are doing a search and no database is selected
if (is_array ($config['calibre_directory']) && is_null (GetUrlParam (DB))) {
$i = 0;
foreach ($config['calibre_directory'] as $key => $value) {
Base::clearDb ();
list ($array, $totalNumber) = Book::getBooksByQuery ($this->query, $this->n, $i);
array_push ($this->entryArray, new Entry ($key, DB . ":query:{$i}",
str_format (localize ("bookword", count($array)), count($array)), "text",
array ( new LinkNavigation ("?" . DB . "={$i}&page=9&query=" . $this->query))));
$i++;
}
return;
}
switch ($currentPage) {
case Base::PAGE_ALL_AUTHORS :
case Base::PAGE_AUTHORS_FIRST_LETTER :
$this->entryArray = Author::getAuthorsByStartingLetter ('%' . $this->query);
break;
default:
list ($this->entryArray, $this->totalNumber) = Book::getBooksByQuery ($this->query, $this->n);
}
} }
} }
@ -512,6 +618,15 @@ class PageBookDetail extends Page
} }
} }
class PageAbout extends Page
{
public function InitializeContent ()
{
$this->title = localize ("about.title");
}
}
abstract class Base abstract class Base
{ {
const PAGE_INDEX = "index"; const PAGE_INDEX = "index";
@ -530,21 +645,51 @@ abstract class Base
const PAGE_BOOK_DETAIL = "13"; const PAGE_BOOK_DETAIL = "13";
const PAGE_ALL_CUSTOMS = "14"; const PAGE_ALL_CUSTOMS = "14";
const PAGE_CUSTOM_DETAIL = "15"; const PAGE_CUSTOM_DETAIL = "15";
const PAGE_ABOUT = "16";
const COMPATIBILITY_XML_ALDIKO = "aldiko"; const COMPATIBILITY_XML_ALDIKO = "aldiko";
private static $db = NULL; private static $db = NULL;
public static function getDbFileName () { public static function getDbList () {
global $config; global $config;
return $config['calibre_directory'] .'metadata.db'; if (is_array ($config['calibre_directory'])) {
return $config['calibre_directory'];
} else {
return array ("" => $config['calibre_directory']);
}
}
public static function getDbName ($database = NULL) {
global $config;
if (is_array ($config['calibre_directory'])) {
if (is_null ($database)) $database = GetUrlParam (DB, 0);
$array = array_keys ($config['calibre_directory']);
return $array[$database];
}
return "";
}
public static function getDbDirectory ($database = NULL) {
global $config;
if (is_array ($config['calibre_directory'])) {
if (is_null ($database)) $database = GetUrlParam (DB, 0);
$array = array_values ($config['calibre_directory']);
return $array[$database];
}
return $config['calibre_directory'];
}
public static function getDbFileName ($database = NULL) {
return self::getDbDirectory ($database) .'metadata.db';
} }
public static function getDb () { public static function getDb ($database = NULL) {
global $config; global $config;
if (is_null (self::$db)) { if (is_null (self::$db)) {
try { try {
self::$db = new PDO('sqlite:'. self::getDbFileName ()); self::$db = new PDO('sqlite:'. self::getDbFileName ($database));
} catch (Exception $e) { } catch (Exception $e) {
header("location: checkconfig.php?err=1"); header("location: checkconfig.php?err=1");
exit(); exit();
@ -553,14 +698,18 @@ abstract class Base
return self::$db; return self::$db;
} }
public static function executeQuery($query, $columns, $filter, $params, $n) { public static function clearDb () {
self::$db = NULL;
}
public static function executeQuery($query, $columns, $filter, $params, $n, $database = NULL) {
global $config; global $config;
$totalResult = -1; $totalResult = -1;
if ($config['cops_max_item_per_page'] != -1 && $n != -1) if ($config['cops_max_item_per_page'] != -1 && $n != -1)
{ {
// First check total number of results // First check total number of results
$result = self::getDb ()->prepare (str_format ($query, "count(*)", $filter)); $result = self::getDb ($database)->prepare (str_format ($query, "count(*)", $filter));
$result->execute ($params); $result->execute ($params);
$totalResult = $result->fetchColumn (); $totalResult = $result->fetchColumn ();
@ -569,10 +718,10 @@ abstract class Base
array_push ($params, ($n - 1) * $config['cops_max_item_per_page'], $config['cops_max_item_per_page']); array_push ($params, ($n - 1) * $config['cops_max_item_per_page'], $config['cops_max_item_per_page']);
} }
$result = self::getDb ()->prepare(str_format ($query, $columns, $filter)); $result = self::getDb ($database)->prepare(str_format ($query, $columns, $filter));
$result->execute ($params); $result->execute ($params);
return array ($totalResult, $result); return array ($totalResult, $result);
} }
} }
?> ?>

View file

@ -12,7 +12,7 @@ require_once('author.php');
require_once('tag.php'); require_once('tag.php');
require_once ("customcolumn.php"); require_once ("customcolumn.php");
require_once('data.php'); require_once('data.php');
require_once('php-epub-meta/epub.php'); require_once('resources/php-epub-meta/epub.php');
// Silly thing because PHP forbid string concatenation in class const // Silly thing because PHP forbid string concatenation in class const
define ('SQL_BOOKS_LEFT_JOIN', "left outer join comments on comments.book = books.id define ('SQL_BOOKS_LEFT_JOIN', "left outer join comments on comments.book = books.id
@ -72,7 +72,7 @@ class Book extends Base {
$this->title = $line->title; $this->title = $line->title;
$this->timestamp = strtotime ($line->timestamp); $this->timestamp = strtotime ($line->timestamp);
$this->pubdate = strtotime ($line->pubdate); $this->pubdate = strtotime ($line->pubdate);
$this->path = $config['calibre_directory'] . $line->path; $this->path = Base::getDbDirectory () . $line->path;
$this->relativePath = $line->path; $this->relativePath = $line->path;
$this->seriesIndex = $line->series_index; $this->seriesIndex = $line->series_index;
$this->comment = $line->comment; $this->comment = $line->comment;
@ -94,15 +94,18 @@ class Book extends Base {
} }
public function getUri () { public function getUri () {
return "?page=".parent::PAGE_BOOK_DETAIL."&amp;id=$this->id"; return "?page=".parent::PAGE_BOOK_DETAIL."&id=$this->id";
} }
public function getDetailUrl () { public function getDetailUrl ($permalink = false) {
global $config; global $config;
if ($config['cops_use_fancyapps'] == 0) { $urlParam = $this->getUri ();
return 'index.php' . $this->getUri (); if (!is_null (GetUrlParam (DB))) $urlParam = addURLParameter ($urlParam, DB, GetUrlParam (DB));
$urlParam = str_replace ("&", "&amp;", $urlParam);
if ($permalink || $config['cops_use_fancyapps'] == 0) {
return 'index.php' . $urlParam;
} else { } else {
return 'bookdetail.php?id=' . $this->id; return 'bookdetail.php' . $urlParam;
} }
} }
@ -117,7 +120,7 @@ class Book extends Base {
return $this->authors; return $this->authors;
} }
public function getFilterString () { public static function getFilterString () {
$filter = getURLParam ("tag", NULL); $filter = getURLParam ("tag", NULL);
if (empty ($filter)) return ""; if (empty ($filter)) return "";
@ -137,17 +140,7 @@ class Book extends Base {
} }
public function getAuthorsName () { public function getAuthorsName () {
$authorList = null; return implode (", ", array_map (function ($author) { return $author->name; }, $this->getAuthors ()));
foreach ($this->getAuthors () as $author) {
if ($authorList) {
$authorList = $authorList . ", " . $author->name;
}
else
{
$authorList = $author->name;
}
}
return $authorList;
} }
public function getSerie () { public function getSerie () {
@ -219,17 +212,7 @@ class Book extends Base {
public function getTagsName () { public function getTagsName () {
$tagList = null; return implode (", ", array_map (function ($tag) { return $tag->name; }, $this->getTags ()));
foreach ($this->getTags () as $tag) {
if ($tagList) {
$tagList = $tagList . ", " . $tag->name;
}
else
{
$tagList = $tag->name;
}
}
return $tagList;
} }
public function getRating () { public function getRating () {
@ -349,15 +332,8 @@ class Book extends Base {
if ($this->hasCover) if ($this->hasCover)
{ {
array_push ($linkArray, Data::getLink ($this, "jpg", "image/jpeg", Link::OPDS_IMAGE_TYPE, "cover.jpg", NULL)); array_push ($linkArray, Data::getLink ($this, "jpg", "image/jpeg", Link::OPDS_IMAGE_TYPE, "cover.jpg", NULL));
$height = "50";
if (preg_match ('/feed.php/', $_SERVER["SCRIPT_NAME"])) { array_push ($linkArray, Data::getLink ($this, "jpg", "image/jpeg", Link::OPDS_THUMBNAIL_TYPE, "cover.jpg", NULL));
$height = $config['cops_opds_thumbnail_height'];
}
else
{
$height = $config['cops_html_thumbnail_height'];
}
array_push ($linkArray, new Link ("fetch.php?id=$this->id&height=" . $height, "image/jpeg", Link::OPDS_THUMBNAIL_TYPE));
} }
foreach ($this->getDatas () as $data) foreach ($this->getDatas () as $data)
@ -393,7 +369,7 @@ class Book extends Base {
$result = array(); $result = array();
$entry = new Entry (localize ("allbooks.title"), $entry = new Entry (localize ("allbooks.title"),
self::ALL_BOOKS_ID, self::ALL_BOOKS_ID,
str_format (localize ("allbooks.alphabetical"), $nBooks), "text", str_format (localize ("allbooks.alphabetical", $nBooks), $nBooks), "text",
array ( new LinkNavigation ("?page=".parent::PAGE_ALL_BOOKS))); array ( new LinkNavigation ("?page=".parent::PAGE_ALL_BOOKS)));
array_push ($result, $entry); array_push ($result, $entry);
$entry = new Entry (localize ("recent.title"), $entry = new Entry (localize ("recent.title"),
@ -451,8 +427,8 @@ where data.book = books.id and data.id = ?');
return NULL; return NULL;
} }
public static function getBooksByQuery($query, $n) { public static function getBooksByQuery($query, $n, $database = NULL) {
return self::getEntryArray (self::SQL_BOOKS_QUERY, array ("%" . $query . "%", "%" . $query . "%"), $n); return self::getEntryArray (self::SQL_BOOKS_QUERY, array ("%" . $query . "%", "%" . $query . "%"), $n, $database);
} }
public static function getAllBooks() { public static function getAllBooks() {
@ -474,8 +450,8 @@ order by substr (upper (sort), 1, 1)");
return self::getEntryArray (self::SQL_BOOKS_BY_FIRST_LETTER, array ($letter . "%"), $n); return self::getEntryArray (self::SQL_BOOKS_BY_FIRST_LETTER, array ($letter . "%"), $n);
} }
public static function getEntryArray ($query, $params, $n) { public static function getEntryArray ($query, $params, $n, $database = NULL) {
list ($totalNumber, $result) = parent::executeQuery ($query, self::BOOK_COLUMNS, self::getFilterString (), $params, $n); list ($totalNumber, $result) = parent::executeQuery ($query, self::BOOK_COLUMNS, self::getFilterString (), $params, $n, $database);
$entryArray = array(); $entryArray = array();
while ($post = $result->fetchObject ()) while ($post = $result->fetchObject ())
{ {

View file

@ -32,7 +32,9 @@ $book->getLinkArray ();
<?php <?php
if ($book->hasCover) { if ($book->hasCover) {
?> ?>
<a href="fetch.php?id=<?php echo $book->id ?>"><img src="fetch.php?id=<?php echo $book->id ?>&amp;height=150" alt="<?php echo localize("i18n.coversection") ?>" /></a> <a href="<?php echo Data::getLink ($book, "jpg", "image/jpeg", Link::OPDS_IMAGE_TYPE, "cover.jpg", NULL)->hrefXhtml () ?>">
<img src="<?php echo Data::getLink ($book, "jpg", "image/jpeg", Link::OPDS_THUMBNAIL_TYPE, "cover.jpg", NULL, NULL, 150)->hrefXhtml () ?>" alt="<?php echo localize("i18n.coversection") ?>" />
</a>
<?php <?php
} }
?> ?>
@ -54,7 +56,7 @@ $book->getLinkArray ();
foreach ($authors as $author) { foreach ($authors as $author) {
if ($i > 0) echo ", "; if ($i > 0) echo ", ";
?> ?>
<a href="index.php<?php echo str_replace ("&", "&amp;", $author->getUri ()) ?>"><?php echo htmlspecialchars ($author->name) ?></a> <a href="<?php $link = new LinkNavigation ($author->getUri ()); echo $link->hrefXhtml () ?>"><?php echo htmlspecialchars ($author->name) ?></a>
<?php <?php
} }
?> ?>
@ -69,7 +71,7 @@ $book->getLinkArray ();
foreach ($tags as $tag) { foreach ($tags as $tag) {
if ($i > 0) echo ", "; if ($i > 0) echo ", ";
?> ?>
<a href="index.php<?php echo str_replace ("&", "&amp;", $tag->getUri ()) ?>"><?php echo htmlspecialchars ($tag->name) ?></a> <a href="<?php $link = new LinkNavigation ($tag->getUri ()); echo $link->hrefXhtml () ?>"><?php echo htmlspecialchars ($tag->name) ?></a>
<?php <?php
} }
?> ?>
@ -79,7 +81,7 @@ $book->getLinkArray ();
if (!is_null ($serie)) if (!is_null ($serie))
{ {
?> ?>
<h3><a href="index.php<?php echo str_replace ("&", "&amp;", $serie->getUri ()) ?>"><?php echo localize("series.title") ?></a>: </h3> <h3><a href="index.php<?php $link = new LinkNavigation ($serie->getUri ()); echo $link->hrefXhtml () ?>"><?php echo localize("series.title") ?></a>: </h3>
<?php echo str_format (localize ("content.series.data"), $book->seriesIndex, htmlspecialchars ($serie->name)) ?> <?php echo str_format (localize ("content.series.data"), $book->seriesIndex, htmlspecialchars ($serie->name)) ?>
<br /> <br />
<?php <?php

View file

@ -74,15 +74,30 @@
?> ?>
</div> </div>
</div> </div>
<div class="entry">
<div class="entryTitle">Check if libxml is properly installed and loaded</div>
<div class="entryContent">
<?php
if (extension_loaded('libxml')) {
echo "OK";
} else {
echo "Please make sure libxml is enabled";
}
?>
</div>
</div>
<?php
$i = 0;
foreach (Base::getDbList () as $name => $database) {
?>
<div class="entry"> <div class="entry">
<div class="entryTitle">Check if Calibre database file exists and is readable</div> <div class="entryTitle">Check if Calibre database file exists and is readable</div>
<div class="entryContent"> <div class="entryContent">
<?php <?php
if (is_readable (Base::getDbFileName ())) { if (is_readable (Base::getDbFileName ($i))) {
echo "OK"; echo "{$name} OK";
} else { } else {
echo "File " . Base::getDbFileName () . " not found, echo "{$name} File " . Base::getDbFileName ($i) . " not found,
Please check Please check
<ul> <ul>
<li>Value of \$config['calibre_directory'] in config_local.php</li> <li>Value of \$config['calibre_directory'] in config_local.php</li>
@ -99,14 +114,33 @@ Please check
<div class="entryContent"> <div class="entryContent">
<?php <?php
try { try {
$db = new PDO('sqlite:'. Base::getDbFileName ()); $db = new PDO('sqlite:'. Base::getDbFileName ($i));
echo "OK"; echo "{$name} OK";
} catch (Exception $e) { } catch (Exception $e) {
echo "If the file is readable, check your php configuration. Exception detail : " . $e; echo "{$name} If the file is readable, check your php configuration. Exception detail : " . $e;
} }
?> ?>
</div> </div>
</div> </div>
<div class="entry">
<div class="entryTitle">Check if Calibre database file contains at least some of the needed tables</div>
<div class="entryContent">
<?php
try {
$db = new PDO('sqlite:'. Base::getDbFileName ($i));
$count = $db->query("select count(*) FROM sqlite_master WHERE type='table' AND name in ('books', 'authors', 'tags', 'series')")->fetchColumn();
if ($count == 4) {
echo "{$name} OK";
} else {
echo "{$name} Not all Calibre tables were found. Are you you're using the correct database.";
}
} catch (Exception $e) {
echo "{$name} If the file is readable, check your php configuration. Exception detail : " . $e;
}
?>
</div>
</div>
<?php $i++; } ?>
</div> </div>
</div> </div>
</body> </body>

View file

@ -13,6 +13,8 @@
* The directory containing calibre's metadata.db file, with sub-directories * The directory containing calibre's metadata.db file, with sub-directories
* containing all the formats. * containing all the formats.
* BEWARE : it has to end with a / * BEWARE : it has to end with a /
* You can enable multiple database with this notation instead of a simple string :
* $config['calibre_directory'] = array ("My database name" => "/home/directory/calibre1/", "My other database name" => "/home/directory/calibre2/");
*/ */
$config['calibre_directory'] = './feedbook/'; $config['calibre_directory'] = './feedbook/';
@ -93,7 +95,7 @@
/* /*
* use URL rewriting for downloading of ebook in HTML catalog * use URL rewriting for downloading of ebook in HTML catalog
* See README for more information * See Github wiki for more information
* 1 : enable * 1 : enable
* 0 : disable * 0 : disable
*/ */
@ -164,4 +166,5 @@
* 0 : No * 0 : No
*/ */
$config['cops_provide_kepub'] = "0"; $config['cops_provide_kepub'] = "0";
?> ?>

View file

@ -68,13 +68,12 @@ class CustomColumn extends Base {
public static function getCount($customId) { public static function getCount($customId) {
$nCustoms = parent::getDb ()->query('select count(*) from ' . self::getTableName ($customId))->fetchColumn(); $nCustoms = parent::getDb ()->query('select count(*) from ' . self::getTableName ($customId))->fetchColumn();
$entry = new Entry (self::getAllTitle ($customId), self::getAllCustomsId ($customId), $entry = new Entry (self::getAllTitle ($customId), self::getAllCustomsId ($customId),
str_format (localize("tags.alphabetical"), $nCustoms), "text", str_format (localize("tags.alphabetical", $nCustoms), $nCustoms), "text",
array ( new LinkNavigation (self::getUriAllCustoms ($customId)))); array ( new LinkNavigation (self::getUriAllCustoms ($customId))));
return $entry; return $entry;
} }
public static function getCustomById ($customId, $id) { public static function getCustomById ($customId, $id) {
$test = 'select id, value as name from ' . self::getTableName ($customId) . ' where id = ?';
$result = parent::getDb ()->prepare('select id, value as name from ' . self::getTableName ($customId) . ' where id = ?'); $result = parent::getDb ()->prepare('select id, value as name from ' . self::getTableName ($customId) . ' where id = ?');
$result->execute (array ($id)); $result->execute (array ($id));
if ($post = $result->fetchObject ()) { if ($post = $result->fetchObject ()) {
@ -84,12 +83,6 @@ class CustomColumn extends Base {
} }
public static function getAllCustoms($customId) { public static function getAllCustoms($customId) {
$test = str_format ("{0} - {1} - {2}", self::getTableName ($customId), self::getTableLinkName ($customId), self::getTableLinkColumn ($customId));
$test = str_format ('select {0}.id as id, {0}.value as name, count(*) as count
from {0}, {1}
where {0}.id = {1}.{2}
group by {0}.id, {0}.value
order by {0}.value', self::getTableName ($customId), self::getTableLinkName ($customId), self::getTableLinkColumn ($customId));
$result = parent::getDb ()->query(str_format ('select {0}.id as id, {0}.value as name, count(*) as count $result = parent::getDb ()->query(str_format ('select {0}.id as id, {0}.value as name, count(*) as count
from {0}, {1} from {0}, {1}
where {0}.id = {1}.{2} where {0}.id = {1}.{2}

View file

@ -95,10 +95,12 @@ class Data extends Base {
if ($config['cops_use_url_rewriting'] == "1") if ($config['cops_use_url_rewriting'] == "1")
{ {
$database = "";
if (!is_null (GetUrlParam (DB))) $database = GetUrlParam (DB) . "/";
if ($config['cops_provide_kepub'] == "1" && preg_match("/Kobo/", $_SERVER['HTTP_USER_AGENT'])) { if ($config['cops_provide_kepub'] == "1" && preg_match("/Kobo/", $_SERVER['HTTP_USER_AGENT'])) {
return "download/" . $this->id . "/" . urlencode ($this->getUpdatedFilenameKepub ()); return "download/" . $this->id . "/" . $database . urlencode ($this->getUpdatedFilenameKepub ());
} else { } else {
return "download/" . $this->id . "/" . urlencode ($this->getFilename ()); return "download/" . $this->id . "/" . $database . urlencode ($this->getFilename ());
} }
} }
else else
@ -107,22 +109,33 @@ class Data extends Base {
} }
} }
public static function getLink ($book, $type, $mime, $rel, $filename, $idData, $title = NULL) public static function getLink ($book, $type, $mime, $rel, $filename, $idData, $title = NULL, $height = NULL)
{ {
global $config; global $config;
$textData = ""; $urlParam = addURLParameter("", "data", $idData);
if (!is_null ($idData))
{
$textData = "&data=" . $idData;
}
if (preg_match ('/^\//', $config['calibre_directory']) || // Linux / if (preg_match ('/^\//', Base::getDbDirectory ()) || // Linux /
preg_match ('/^\w\:/', $config['calibre_directory']) || // Windows X: preg_match ('/^\w\:/', Base::getDbDirectory ()) || // Windows X:
$rel == Link::OPDS_THUMBNAIL_TYPE ||
($type == "epub" && $config['cops_update_epub-metadata'])) ($type == "epub" && $config['cops_update_epub-metadata']))
{ {
if ($type != "jpg") $textData .= "&type=" . $type; if ($type != "jpg") $urlParam = addURLParameter($urlParam, "type", $type);
return new Link ("fetch.php?id=$book->id" . $textData, $mime, $rel, $title); if ($rel == Link::OPDS_THUMBNAIL_TYPE) {
if (is_null ($height)) {
if (preg_match ('/feed.php/', $_SERVER["SCRIPT_NAME"])) {
$height = $config['cops_opds_thumbnail_height'];
}
else
{
$height = $config['cops_html_thumbnail_height'];
}
}
$urlParam = addURLParameter($urlParam, "height", $height);
}
$urlParam = addURLParameter($urlParam, "id", $book->id);
if (!is_null (GetUrlParam (DB))) $urlParam = addURLParameter ($urlParam, DB, GetUrlParam (DB));
return new Link ("fetch.php?" . $urlParam, $mime, $rel, $title);
} }
else else
{ {

View file

@ -1,45 +0,0 @@
/*! fancyBox v2.1.3 fancyapps.com | fancyapps.com/fancybox/#license */
(function(B,x,f,q){var r=f(B),m=f(x),b=f.fancybox=function(){b.open.apply(this,arguments)},u=null,n=x.createTouch!==q,s=function(a){return a&&a.hasOwnProperty&&a instanceof f},p=function(a){return a&&"string"===f.type(a)},E=function(a){return p(a)&&0<a.indexOf("%")},k=function(a,d){var e=parseInt(a,10)||0;d&&E(a)&&(e*=b.getViewport()[d]/100);return Math.ceil(e)},v=function(a,b){return k(a,b)+"px"};f.extend(b,{version:"2.1.3",defaults:{padding:15,margin:20,width:800,height:600,minWidth:100,minHeight:100,
maxWidth:9999,maxHeight:9999,autoSize:!0,autoHeight:!1,autoWidth:!1,autoResize:!0,autoCenter:!n,fitToView:!0,aspectRatio:!1,topRatio:0.5,leftRatio:0.5,scrolling:"auto",wrapCSS:"",arrows:!0,closeBtn:!0,closeClick:!1,nextClick:!1,mouseWheel:!0,autoPlay:!1,playSpeed:3E3,preload:3,modal:!1,loop:!0,ajax:{dataType:"html",headers:{"X-fancyBox":!0}},iframe:{scrolling:"auto",preload:!0},swf:{wmode:"transparent",allowfullscreen:"true",allowscriptaccess:"always"},keys:{next:{13:"left",34:"up",39:"left",40:"up"},
prev:{8:"right",33:"down",37:"right",38:"down"},close:[27],play:[32],toggle:[70]},direction:{next:"left",prev:"right"},scrollOutside:!0,index:0,type:null,href:null,content:null,title:null,tpl:{wrap:'<div class="fancybox-wrap" tabIndex="-1"><div class="fancybox-skin"><div class="fancybox-outer"><div class="fancybox-inner"></div></div></div></div>',image:'<img class="fancybox-image" src="{href}" alt="" />',iframe:'<iframe id="fancybox-frame{rnd}" name="fancybox-frame{rnd}" class="fancybox-iframe" frameborder="0" vspace="0" hspace="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen'+
(f.browser.msie?' allowtransparency="true"':"")+"></iframe>",error:'<p class="fancybox-error">The requested content cannot be loaded.<br/>Please try again later.</p>',closeBtn:'<a title="Close" class="fancybox-item fancybox-close" href="javascript:;"></a>',next:'<a title="Next" class="fancybox-nav fancybox-next" href="javascript:;"><span></span></a>',prev:'<a title="Previous" class="fancybox-nav fancybox-prev" href="javascript:;"><span></span></a>'},openEffect:"fade",openSpeed:250,openEasing:"swing",
openOpacity:!0,openMethod:"zoomIn",closeEffect:"fade",closeSpeed:250,closeEasing:"swing",closeOpacity:!0,closeMethod:"zoomOut",nextEffect:"elastic",nextSpeed:250,nextEasing:"swing",nextMethod:"changeIn",prevEffect:"elastic",prevSpeed:250,prevEasing:"swing",prevMethod:"changeOut",helpers:{overlay:!0,title:!0},onCancel:f.noop,beforeLoad:f.noop,afterLoad:f.noop,beforeShow:f.noop,afterShow:f.noop,beforeChange:f.noop,beforeClose:f.noop,afterClose:f.noop},group:{},opts:{},previous:null,coming:null,current:null,
isActive:!1,isOpen:!1,isOpened:!1,wrap:null,skin:null,outer:null,inner:null,player:{timer:null,isActive:!1},ajaxLoad:null,imgPreload:null,transitions:{},helpers:{},open:function(a,d){if(a&&(f.isPlainObject(d)||(d={}),!1!==b.close(!0)))return f.isArray(a)||(a=s(a)?f(a).get():[a]),f.each(a,function(e,c){var j={},g,h,i,l,k;"object"===f.type(c)&&(c.nodeType&&(c=f(c)),s(c)?(j={href:c.data("fancybox-href")||c.attr("href"),title:c.data("fancybox-title")||c.attr("title"),isDom:!0,element:c},f.metadata&&f.extend(!0,
j,c.metadata())):j=c);g=d.href||j.href||(p(c)?c:null);h=d.title!==q?d.title:j.title||"";l=(i=d.content||j.content)?"html":d.type||j.type;!l&&j.isDom&&(l=c.data("fancybox-type"),l||(l=(l=c.prop("class").match(/fancybox\.(\w+)/))?l[1]:null));p(g)&&(l||(b.isImage(g)?l="image":b.isSWF(g)?l="swf":"#"===g.charAt(0)?l="inline":p(c)&&(l="html",i=c)),"ajax"===l&&(k=g.split(/\s+/,2),g=k.shift(),k=k.shift()));i||("inline"===l?g?i=f(p(g)?g.replace(/.*(?=#[^\s]+$)/,""):g):j.isDom&&(i=c):"html"===l?i=g:!l&&(!g&&
j.isDom)&&(l="inline",i=c));f.extend(j,{href:g,type:l,content:i,title:h,selector:k});a[e]=j}),b.opts=f.extend(!0,{},b.defaults,d),d.keys!==q&&(b.opts.keys=d.keys?f.extend({},b.defaults.keys,d.keys):!1),b.group=a,b._start(b.opts.index)},cancel:function(){var a=b.coming;a&&!1!==b.trigger("onCancel")&&(b.hideLoading(),b.ajaxLoad&&b.ajaxLoad.abort(),b.ajaxLoad=null,b.imgPreload&&(b.imgPreload.onload=b.imgPreload.onerror=null),a.wrap&&a.wrap.stop(!0,!0).trigger("onReset").remove(),b.coming=null,b.current||
b._afterZoomOut(a))},close:function(a){b.cancel();!1!==b.trigger("beforeClose")&&(b.unbindEvents(),b.isActive&&(!b.isOpen||!0===a?(f(".fancybox-wrap").stop(!0).trigger("onReset").remove(),b._afterZoomOut()):(b.isOpen=b.isOpened=!1,b.isClosing=!0,f(".fancybox-item, .fancybox-nav").remove(),b.wrap.stop(!0,!0).removeClass("fancybox-opened"),b.transitions[b.current.closeMethod]())))},play:function(a){var d=function(){clearTimeout(b.player.timer)},e=function(){d();b.current&&b.player.isActive&&(b.player.timer=
setTimeout(b.next,b.current.playSpeed))},c=function(){d();f("body").unbind(".player");b.player.isActive=!1;b.trigger("onPlayEnd")};if(!0===a||!b.player.isActive&&!1!==a){if(b.current&&(b.current.loop||b.current.index<b.group.length-1))b.player.isActive=!0,f("body").bind({"afterShow.player onUpdate.player":e,"onCancel.player beforeClose.player":c,"beforeLoad.player":d}),e(),b.trigger("onPlayStart")}else c()},next:function(a){var d=b.current;d&&(p(a)||(a=d.direction.next),b.jumpto(d.index+1,a,"next"))},
prev:function(a){var d=b.current;d&&(p(a)||(a=d.direction.prev),b.jumpto(d.index-1,a,"prev"))},jumpto:function(a,d,e){var c=b.current;c&&(a=k(a),b.direction=d||c.direction[a>=c.index?"next":"prev"],b.router=e||"jumpto",c.loop&&(0>a&&(a=c.group.length+a%c.group.length),a%=c.group.length),c.group[a]!==q&&(b.cancel(),b._start(a)))},reposition:function(a,d){var e=b.current,c=e?e.wrap:null,j;c&&(j=b._getPosition(d),a&&"scroll"===a.type?(delete j.position,c.stop(!0,!0).animate(j,200)):(c.css(j),e.pos=f.extend({},
e.dim,j)))},update:function(a){var d=a&&a.type,e=!d||"orientationchange"===d;e&&(clearTimeout(u),u=null);b.isOpen&&!u&&(u=setTimeout(function(){var c=b.current;c&&!b.isClosing&&(b.wrap.removeClass("fancybox-tmp"),(e||"load"===d||"resize"===d&&c.autoResize)&&b._setDimension(),"scroll"===d&&c.canShrink||b.reposition(a),b.trigger("onUpdate"),u=null)},e&&!n?0:300))},toggle:function(a){b.isOpen&&(b.current.fitToView="boolean"===f.type(a)?a:!b.current.fitToView,n&&(b.wrap.removeAttr("style").addClass("fancybox-tmp"),
b.trigger("onUpdate")),b.update())},hideLoading:function(){m.unbind(".loading");f("#fancybox-loading").remove()},showLoading:function(){var a,d;b.hideLoading();a=f('<div id="fancybox-loading"><div></div></div>').click(b.cancel).appendTo("body");m.bind("keydown.loading",function(a){if(27===(a.which||a.keyCode))a.preventDefault(),b.cancel()});b.defaults.fixed||(d=b.getViewport(),a.css({position:"absolute",top:0.5*d.h+d.y,left:0.5*d.w+d.x}))},getViewport:function(){var a=b.current&&b.current.locked||
!1,d={x:r.scrollLeft(),y:r.scrollTop()};a?(d.w=a[0].clientWidth,d.h=a[0].clientHeight):(d.w=n&&B.innerWidth?B.innerWidth:r.width(),d.h=n&&B.innerHeight?B.innerHeight:r.height());return d},unbindEvents:function(){b.wrap&&s(b.wrap)&&b.wrap.unbind(".fb");m.unbind(".fb");r.unbind(".fb")},bindEvents:function(){var a=b.current,d;a&&(r.bind("orientationchange.fb"+(n?"":" resize.fb")+(a.autoCenter&&!a.locked?" scroll.fb":""),b.update),(d=a.keys)&&m.bind("keydown.fb",function(e){var c=e.which||e.keyCode,j=
e.target||e.srcElement;if(27===c&&b.coming)return!1;!e.ctrlKey&&(!e.altKey&&!e.shiftKey&&!e.metaKey&&(!j||!j.type&&!f(j).is("[contenteditable]")))&&f.each(d,function(d,j){if(1<a.group.length&&j[c]!==q)return b[d](j[c]),e.preventDefault(),!1;if(-1<f.inArray(c,j))return b[d](),e.preventDefault(),!1})}),f.fn.mousewheel&&a.mouseWheel&&b.wrap.bind("mousewheel.fb",function(d,c,j,g){for(var h=f(d.target||null),i=!1;h.length&&!i&&!h.is(".fancybox-skin")&&!h.is(".fancybox-wrap");)i=h[0]&&!(h[0].style.overflow&&
"hidden"===h[0].style.overflow)&&(h[0].clientWidth&&h[0].scrollWidth>h[0].clientWidth||h[0].clientHeight&&h[0].scrollHeight>h[0].clientHeight),h=f(h).parent();if(0!==c&&!i&&1<b.group.length&&!a.canShrink){if(0<g||0<j)b.prev(0<g?"down":"left");else if(0>g||0>j)b.next(0>g?"up":"right");d.preventDefault()}}))},trigger:function(a,d){var e,c=d||b.coming||b.current;if(c){f.isFunction(c[a])&&(e=c[a].apply(c,Array.prototype.slice.call(arguments,1)));if(!1===e)return!1;c.helpers&&f.each(c.helpers,function(d,
e){e&&(b.helpers[d]&&f.isFunction(b.helpers[d][a]))&&(e=f.extend(!0,{},b.helpers[d].defaults,e),b.helpers[d][a](e,c))});f.event.trigger(a+".fb")}},isImage:function(a){return p(a)&&a.match(/(^data:image\/.*,)|(\.(jp(e|g|eg)|gif|png|bmp|webp)((\?|#).*)?$)/i)},isSWF:function(a){return p(a)&&a.match(/\.(swf)((\?|#).*)?$/i)},_start:function(a){var d={},e,c,a=k(a);e=b.group[a]||null;if(!e)return!1;d=f.extend(!0,{},b.opts,e);e=d.margin;c=d.padding;"number"===f.type(e)&&(d.margin=[e,e,e,e]);"number"===f.type(c)&&
(d.padding=[c,c,c,c]);d.modal&&f.extend(!0,d,{closeBtn:!1,closeClick:!1,nextClick:!1,arrows:!1,mouseWheel:!1,keys:null,helpers:{overlay:{closeClick:!1}}});d.autoSize&&(d.autoWidth=d.autoHeight=!0);"auto"===d.width&&(d.autoWidth=!0);"auto"===d.height&&(d.autoHeight=!0);d.group=b.group;d.index=a;b.coming=d;if(!1===b.trigger("beforeLoad"))b.coming=null;else{c=d.type;e=d.href;if(!c)return b.coming=null,b.current&&b.router&&"jumpto"!==b.router?(b.current.index=a,b[b.router](b.direction)):!1;b.isActive=
!0;if("image"===c||"swf"===c)d.autoHeight=d.autoWidth=!1,d.scrolling="visible";"image"===c&&(d.aspectRatio=!0);"iframe"===c&&n&&(d.scrolling="scroll");d.wrap=f(d.tpl.wrap).addClass("fancybox-"+(n?"mobile":"desktop")+" fancybox-type-"+c+" fancybox-tmp "+d.wrapCSS).appendTo(d.parent||"body");f.extend(d,{skin:f(".fancybox-skin",d.wrap),outer:f(".fancybox-outer",d.wrap),inner:f(".fancybox-inner",d.wrap)});f.each(["Top","Right","Bottom","Left"],function(a,b){d.skin.css("padding"+b,v(d.padding[a]))});b.trigger("onReady");
if("inline"===c||"html"===c){if(!d.content||!d.content.length)return b._error("content")}else if(!e)return b._error("href");"image"===c?b._loadImage():"ajax"===c?b._loadAjax():"iframe"===c?b._loadIframe():b._afterLoad()}},_error:function(a){f.extend(b.coming,{type:"html",autoWidth:!0,autoHeight:!0,minWidth:0,minHeight:0,scrolling:"no",hasError:a,content:b.coming.tpl.error});b._afterLoad()},_loadImage:function(){var a=b.imgPreload=new Image;a.onload=function(){this.onload=this.onerror=null;b.coming.width=
this.width;b.coming.height=this.height;b._afterLoad()};a.onerror=function(){this.onload=this.onerror=null;b._error("image")};a.src=b.coming.href;!0!==a.complete&&b.showLoading()},_loadAjax:function(){var a=b.coming;b.showLoading();b.ajaxLoad=f.ajax(f.extend({},a.ajax,{url:a.href,error:function(a,e){b.coming&&"abort"!==e?b._error("ajax",a):b.hideLoading()},success:function(d,e){"success"===e&&(a.content=d,b._afterLoad())}}))},_loadIframe:function(){var a=b.coming,d=f(a.tpl.iframe.replace(/\{rnd\}/g,
(new Date).getTime())).attr("scrolling",n?"auto":a.iframe.scrolling).attr("src",a.href);f(a.wrap).bind("onReset",function(){try{f(this).find("iframe").hide().attr("src","//about:blank").end().empty()}catch(a){}});a.iframe.preload&&(b.showLoading(),d.one("load",function(){f(this).data("ready",1);n||f(this).bind("load.fb",b.update);f(this).parents(".fancybox-wrap").width("100%").removeClass("fancybox-tmp").show();b._afterLoad()}));a.content=d.appendTo(a.inner);a.iframe.preload||b._afterLoad()},_preloadImages:function(){var a=
b.group,d=b.current,e=a.length,c=d.preload?Math.min(d.preload,e-1):0,f,g;for(g=1;g<=c;g+=1)f=a[(d.index+g)%e],"image"===f.type&&f.href&&((new Image).src=f.href)},_afterLoad:function(){var a=b.coming,d=b.current,e,c,j,g,h;b.hideLoading();if(a&&!1!==b.isActive)if(!1===b.trigger("afterLoad",a,d))a.wrap.stop(!0).trigger("onReset").remove(),b.coming=null;else{d&&(b.trigger("beforeChange",d),d.wrap.stop(!0).removeClass("fancybox-opened").find(".fancybox-item, .fancybox-nav").remove());b.unbindEvents();
e=a.content;c=a.type;j=a.scrolling;f.extend(b,{wrap:a.wrap,skin:a.skin,outer:a.outer,inner:a.inner,current:a,previous:d});g=a.href;switch(c){case "inline":case "ajax":case "html":a.selector?e=f("<div>").html(e).find(a.selector):s(e)&&(e.data("fancybox-placeholder")||e.data("fancybox-placeholder",f('<div class="fancybox-placeholder"></div>').insertAfter(e).hide()),e=e.show().detach(),a.wrap.bind("onReset",function(){f(this).find(e).length&&e.hide().replaceAll(e.data("fancybox-placeholder")).data("fancybox-placeholder",
!1)}));break;case "image":e=a.tpl.image.replace("{href}",g);break;case "swf":e='<object id="fancybox-swf" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="100%" height="100%"><param name="movie" value="'+g+'"></param>',h="",f.each(a.swf,function(a,b){e+='<param name="'+a+'" value="'+b+'"></param>';h+=" "+a+'="'+b+'"'}),e+='<embed src="'+g+'" type="application/x-shockwave-flash" width="100%" height="100%"'+h+"></embed></object>"}(!s(e)||!e.parent().is(a.inner))&&a.inner.append(e);b.trigger("beforeShow");
a.inner.css("overflow","yes"===j?"scroll":"no"===j?"hidden":j);b._setDimension();b.reposition();b.isOpen=!1;b.coming=null;b.bindEvents();if(b.isOpened){if(d.prevMethod)b.transitions[d.prevMethod]()}else f(".fancybox-wrap").not(a.wrap).stop(!0).trigger("onReset").remove();b.transitions[b.isOpened?a.nextMethod:a.openMethod]();b._preloadImages()}},_setDimension:function(){var a=b.getViewport(),d=0,e=!1,c=!1,e=b.wrap,j=b.skin,g=b.inner,h=b.current,c=h.width,i=h.height,l=h.minWidth,t=h.minHeight,m=h.maxWidth,
n=h.maxHeight,r=h.scrolling,p=h.scrollOutside?h.scrollbarWidth:0,w=h.margin,y=k(w[1]+w[3]),q=k(w[0]+w[2]),x,z,s,C,A,F,B,D,u;e.add(j).add(g).width("auto").height("auto").removeClass("fancybox-tmp");w=k(j.outerWidth(!0)-j.width());x=k(j.outerHeight(!0)-j.height());z=y+w;s=q+x;C=E(c)?(a.w-z)*k(c)/100:c;A=E(i)?(a.h-s)*k(i)/100:i;if("iframe"===h.type){if(u=h.content,h.autoHeight&&1===u.data("ready"))try{u[0].contentWindow.document.location&&(g.width(C).height(9999),F=u.contents().find("body"),p&&F.css("overflow-x",
"hidden"),A=F.height())}catch(G){}}else if(h.autoWidth||h.autoHeight)g.addClass("fancybox-tmp"),h.autoWidth||g.width(C),h.autoHeight||g.height(A),h.autoWidth&&(C=g.width()),h.autoHeight&&(A=g.height()),g.removeClass("fancybox-tmp");c=k(C);i=k(A);D=C/A;l=k(E(l)?k(l,"w")-z:l);m=k(E(m)?k(m,"w")-z:m);t=k(E(t)?k(t,"h")-s:t);n=k(E(n)?k(n,"h")-s:n);F=m;B=n;h.fitToView&&(m=Math.min(a.w-z,m),n=Math.min(a.h-s,n));z=a.w-y;q=a.h-q;h.aspectRatio?(c>m&&(c=m,i=k(c/D)),i>n&&(i=n,c=k(i*D)),c<l&&(c=l,i=k(c/D)),i<t&&
(i=t,c=k(i*D))):(c=Math.max(l,Math.min(c,m)),h.autoHeight&&"iframe"!==h.type&&(g.width(c),i=g.height()),i=Math.max(t,Math.min(i,n)));if(h.fitToView)if(g.width(c).height(i),e.width(c+w),a=e.width(),y=e.height(),h.aspectRatio)for(;(a>z||y>q)&&(c>l&&i>t)&&!(19<d++);)i=Math.max(t,Math.min(n,i-10)),c=k(i*D),c<l&&(c=l,i=k(c/D)),c>m&&(c=m,i=k(c/D)),g.width(c).height(i),e.width(c+w),a=e.width(),y=e.height();else c=Math.max(l,Math.min(c,c-(a-z))),i=Math.max(t,Math.min(i,i-(y-q)));p&&("auto"===r&&i<A&&c+w+
p<z)&&(c+=p);g.width(c).height(i);e.width(c+w);a=e.width();y=e.height();e=(a>z||y>q)&&c>l&&i>t;c=h.aspectRatio?c<F&&i<B&&c<C&&i<A:(c<F||i<B)&&(c<C||i<A);f.extend(h,{dim:{width:v(a),height:v(y)},origWidth:C,origHeight:A,canShrink:e,canExpand:c,wPadding:w,hPadding:x,wrapSpace:y-j.outerHeight(!0),skinSpace:j.height()-i});!u&&(h.autoHeight&&i>t&&i<n&&!c)&&g.height("auto")},_getPosition:function(a){var d=b.current,e=b.getViewport(),c=d.margin,f=b.wrap.width()+c[1]+c[3],g=b.wrap.height()+c[0]+c[2],c={position:"absolute",
top:c[0],left:c[3]};d.autoCenter&&d.fixed&&!a&&g<=e.h&&f<=e.w?c.position="fixed":d.locked||(c.top+=e.y,c.left+=e.x);c.top=v(Math.max(c.top,c.top+(e.h-g)*d.topRatio));c.left=v(Math.max(c.left,c.left+(e.w-f)*d.leftRatio));return c},_afterZoomIn:function(){var a=b.current;a&&(b.isOpen=b.isOpened=!0,b.wrap.css("overflow","visible").addClass("fancybox-opened"),b.update(),(a.closeClick||a.nextClick&&1<b.group.length)&&b.inner.css("cursor","pointer").bind("click.fb",function(d){!f(d.target).is("a")&&!f(d.target).parent().is("a")&&
(d.preventDefault(),b[a.closeClick?"close":"next"]())}),a.closeBtn&&f(a.tpl.closeBtn).appendTo(b.skin).bind(n?"touchstart.fb":"click.fb",function(a){a.preventDefault();b.close()}),a.arrows&&1<b.group.length&&((a.loop||0<a.index)&&f(a.tpl.prev).appendTo(b.outer).bind("click.fb",b.prev),(a.loop||a.index<b.group.length-1)&&f(a.tpl.next).appendTo(b.outer).bind("click.fb",b.next)),b.trigger("afterShow"),!a.loop&&a.index===a.group.length-1?b.play(!1):b.opts.autoPlay&&!b.player.isActive&&(b.opts.autoPlay=
!1,b.play()))},_afterZoomOut:function(a){a=a||b.current;f(".fancybox-wrap").trigger("onReset").remove();f.extend(b,{group:{},opts:{},router:!1,current:null,isActive:!1,isOpened:!1,isOpen:!1,isClosing:!1,wrap:null,skin:null,outer:null,inner:null});b.trigger("afterClose",a)}});b.transitions={getOrigPosition:function(){var a=b.current,d=a.element,e=a.orig,c={},f=50,g=50,h=a.hPadding,i=a.wPadding,l=b.getViewport();!e&&(a.isDom&&d.is(":visible"))&&(e=d.find("img:first"),e.length||(e=d));s(e)?(c=e.offset(),
e.is("img")&&(f=e.outerWidth(),g=e.outerHeight())):(c.top=l.y+(l.h-g)*a.topRatio,c.left=l.x+(l.w-f)*a.leftRatio);if("fixed"===b.wrap.css("position")||a.locked)c.top-=l.y,c.left-=l.x;return c={top:v(c.top-h*a.topRatio),left:v(c.left-i*a.leftRatio),width:v(f+i),height:v(g+h)}},step:function(a,d){var e,c,f=d.prop;c=b.current;var g=c.wrapSpace,h=c.skinSpace;if("width"===f||"height"===f)e=d.end===d.start?1:(a-d.start)/(d.end-d.start),b.isClosing&&(e=1-e),c="width"===f?c.wPadding:c.hPadding,c=a-c,b.skin[f](k("width"===
f?c:c-g*e)),b.inner[f](k("width"===f?c:c-g*e-h*e))},zoomIn:function(){var a=b.current,d=a.pos,e=a.openEffect,c="elastic"===e,j=f.extend({opacity:1},d);delete j.position;c?(d=this.getOrigPosition(),a.openOpacity&&(d.opacity=0.1)):"fade"===e&&(d.opacity=0.1);b.wrap.css(d).animate(j,{duration:"none"===e?0:a.openSpeed,easing:a.openEasing,step:c?this.step:null,complete:b._afterZoomIn})},zoomOut:function(){var a=b.current,d=a.closeEffect,e="elastic"===d,c={opacity:0.1};e&&(c=this.getOrigPosition(),a.closeOpacity&&
(c.opacity=0.1));b.wrap.animate(c,{duration:"none"===d?0:a.closeSpeed,easing:a.closeEasing,step:e?this.step:null,complete:b._afterZoomOut})},changeIn:function(){var a=b.current,d=a.nextEffect,e=a.pos,c={opacity:1},f=b.direction,g;e.opacity=0.1;"elastic"===d&&(g="down"===f||"up"===f?"top":"left","down"===f||"right"===f?(e[g]=v(k(e[g])-200),c[g]="+=200px"):(e[g]=v(k(e[g])+200),c[g]="-=200px"));"none"===d?b._afterZoomIn():b.wrap.css(e).animate(c,{duration:a.nextSpeed,easing:a.nextEasing,complete:function(){setTimeout(b._afterZoomIn,
20)}})},changeOut:function(){var a=b.previous,d=a.prevEffect,e={opacity:0.1},c=b.direction;"elastic"===d&&(e["down"===c||"up"===c?"top":"left"]=("up"===c||"left"===c?"-":"+")+"=200px");a.wrap.animate(e,{duration:"none"===d?0:a.prevSpeed,easing:a.prevEasing,complete:function(){f(this).trigger("onReset").remove()}})}};b.helpers.overlay={defaults:{closeClick:!0,speedOut:200,showEarly:!0,css:{},locked:!n,fixed:!0},overlay:null,fixed:!1,create:function(a){a=f.extend({},this.defaults,a);this.overlay&&this.close();
this.overlay=f('<div class="fancybox-overlay"></div>').appendTo("body");this.fixed=!1;a.fixed&&b.defaults.fixed&&(this.overlay.addClass("fancybox-overlay-fixed"),this.fixed=!0)},open:function(a){var d=this,a=f.extend({},this.defaults,a);this.overlay?this.overlay.unbind(".overlay").width("auto").height("auto"):this.create(a);this.fixed||(r.bind("resize.overlay",f.proxy(this.update,this)),this.update());a.closeClick&&this.overlay.bind("click.overlay",function(a){f(a.target).hasClass("fancybox-overlay")&&
(b.isActive?b.close():d.close())});this.overlay.css(a.css).show()},close:function(){f(".fancybox-overlay").remove();r.unbind("resize.overlay");this.overlay=null;!1!==this.margin&&(f("body").css("margin-right",this.margin),this.margin=!1);this.el&&this.el.removeClass("fancybox-lock")},update:function(){var a="100%",b;this.overlay.width(a).height("100%");f.browser.msie?(b=Math.max(x.documentElement.offsetWidth,x.body.offsetWidth),m.width()>b&&(a=m.width())):m.width()>r.width()&&(a=m.width());this.overlay.width(a).height(m.height())},
onReady:function(a,b){f(".fancybox-overlay").stop(!0,!0);this.overlay||(this.margin=m.height()>r.height()||"scroll"===f("body").css("overflow-y")?f("body").css("margin-right"):!1,this.el=x.all&&!x.querySelector?f("html"):f("body"),this.create(a));a.locked&&this.fixed&&(b.locked=this.overlay.append(b.wrap),b.fixed=!1);!0===a.showEarly&&this.beforeShow.apply(this,arguments)},beforeShow:function(a,b){b.locked&&(this.el.addClass("fancybox-lock"),!1!==this.margin&&f("body").css("margin-right",k(this.margin)+
b.scrollbarWidth));this.open(a)},onUpdate:function(){this.fixed||this.update()},afterClose:function(a){this.overlay&&!b.isActive&&this.overlay.fadeOut(a.speedOut,f.proxy(this.close,this))}};b.helpers.title={defaults:{type:"float",position:"bottom"},beforeShow:function(a){var d=b.current,e=d.title,c=a.type;f.isFunction(e)&&(e=e.call(d.element,d));if(p(e)&&""!==f.trim(e)){d=f('<div class="fancybox-title fancybox-title-'+c+'-wrap">'+e+"</div>");switch(c){case "inside":c=b.skin;break;case "outside":c=
b.wrap;break;case "over":c=b.inner;break;default:c=b.skin,d.appendTo("body"),f.browser.msie&&d.width(d.width()),d.wrapInner('<span class="child"></span>'),b.current.margin[2]+=Math.abs(k(d.css("margin-bottom")))}d["top"===a.position?"prependTo":"appendTo"](c)}}};f.fn.fancybox=function(a){var d,e=f(this),c=this.selector||"",j=function(g){var h=f(this).blur(),i=d,j,k;!g.ctrlKey&&(!g.altKey&&!g.shiftKey&&!g.metaKey)&&!h.is(".fancybox-wrap")&&(j=a.groupAttr||"data-fancybox-group",k=h.attr(j),k||(j="rel",
k=h.get(0)[j]),k&&(""!==k&&"nofollow"!==k)&&(h=c.length?f(c):e,h=h.filter("["+j+'="'+k+'"]'),i=h.index(this)),a.index=i,!1!==b.open(h,a)&&g.preventDefault())},a=a||{};d=a.index||0;!c||!1===a.live?e.unbind("click.fb-start").bind("click.fb-start",j):m.undelegate(c,"click.fb-start").delegate(c+":not('.fancybox-item, .fancybox-nav')","click.fb-start",j);this.filter("[data-fancybox-start=1]").trigger("click");return this};m.ready(function(){f.scrollbarWidth===q&&(f.scrollbarWidth=function(){var a=f('<div style="width:50px;height:50px;overflow:auto"><div/></div>').appendTo("body"),
b=a.children(),b=b.innerWidth()-b.height(99).innerWidth();a.remove();return b});if(f.support.fixedPosition===q){var a=f.support,d=f('<div style="position:fixed;top:20px;"></div>').appendTo("body"),e=20===d[0].offsetTop||15===d[0].offsetTop;d.remove();a.fixedPosition=e}f.extend(b.defaults,{scrollbarWidth:f.scrollbarWidth(),fixed:f.support.fixedPosition,parent:f("body")})})})(window,document,jQuery);

View file

@ -100,7 +100,7 @@
$dir = $config['calibre_internal_directory']; $dir = $config['calibre_internal_directory'];
if (empty ($config['calibre_internal_directory'])) { if (empty ($config['calibre_internal_directory'])) {
$dir = $config['calibre_directory']; $dir = Base::getDbDirectory ();
} }
if (empty ($config['cops_x_accel_redirect'])) { if (empty ($config['cops_x_accel_redirect'])) {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

View file

@ -24,11 +24,12 @@
$withToolbar = false; $withToolbar = false;
if (!isset($_COOKIE['toolbar'])) $withToolbar = true; if (!isset($_COOKIE['toolbar'])) $withToolbar = true;
header ("Content-Type:application/xhtml+xml"); header ("Content-Type:application/xhtml+xml;charset=utf-8");
$page = getURLParam ("page", Base::PAGE_INDEX); $page = getURLParam ("page", Base::PAGE_INDEX);
$query = getURLParam ("query"); $query = getURLParam ("query");
$qid = getURLParam ("id"); $qid = getURLParam ("id");
$n = getURLParam ("n", "1"); $n = getURLParam ("n", "1");
$database = GetUrlParam (DB);
$currentPage = Page::getPage ($page, $qid, $query, $n); $currentPage = Page::getPage ($page, $qid, $query, $n);
$currentPage->InitializeContent (); $currentPage->InitializeContent ();
@ -52,13 +53,15 @@
<meta http-equiv="imagetoolbar" content="no" /> <meta http-equiv="imagetoolbar" content="no" />
<meta name="viewport" content="width=device-width, height=device-height, user-scalable=no" /> <meta name="viewport" content="width=device-width, height=device-height, user-scalable=no" />
<title><?php echo htmlspecialchars ($currentPage->title) ?></title> <title><?php echo htmlspecialchars ($currentPage->title) ?></title>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7/jquery.min.js"></script> <script type="text/javascript" src="<?php echo getUrlWithVersion("js/jquery-1.9.1.min.js") ?>"></script>
<script type="text/javascript" src="fancybox/jquery.fancybox.pack.js?v=2.1.3"></script>
<script type="text/javascript" src="<?php echo getUrlWithVersion("js/jquery.sortElements.js") ?>"></script>
<script type="text/javascript" src="<?php echo getUrlWithVersion("js/jquery.cookies.js") ?>"></script> <script type="text/javascript" src="<?php echo getUrlWithVersion("js/jquery.cookies.js") ?>"></script>
<link rel="related" href="feed.php" type="application/atom+xml;profile=opds-catalog" title="<?php echo $config['cops_title_default']; ?>" /> <?php if ($config['cops_use_fancyapps'] == 1) { ?>
<script type="text/javascript" src="<?php echo getUrlWithVersion("resources/fancybox/jquery.fancybox.pack.js") ?>"></script>
<link rel="stylesheet" type="text/css" href="<?php echo getUrlWithVersion("resources/fancybox/jquery.fancybox.css") ?>" media="screen" />
<?php } ?>
<script type="text/javascript" src="<?php echo getUrlWithVersion("js/jquery.sortElements.js") ?>"></script>
<link rel="related" href="<?php echo $config['cops_full_url'] ?>feed.php" type="application/atom+xml;profile=opds-catalog" title="<?php echo $config['cops_title_default']; ?>" />
<link rel="icon" type="image/vnd.microsoft.icon" href="<?php echo $currentPage->favicon ?>" /> <link rel="icon" type="image/vnd.microsoft.icon" href="<?php echo $currentPage->favicon ?>" />
<link rel="stylesheet" type="text/css" href="fancybox/jquery.fancybox.css?v=2.1.3" media="screen" />
<link rel="stylesheet" type="text/css" href="<?php echo getUrlWithVersion("style.css") ?>" media="screen" /> <link rel="stylesheet" type="text/css" href="<?php echo getUrlWithVersion("style.css") ?>" media="screen" />
<link rel="stylesheet" href="//normalize-css.googlecode.com/svn/trunk/normalize.css" /> <link rel="stylesheet" href="//normalize-css.googlecode.com/svn/trunk/normalize.css" />
<link href='http://fonts.googleapis.com/css?family=Open+Sans:400,300italic,800,300,400italic,600,600italic,700,700italic,800italic' rel='stylesheet' type='text/css' /> <link href='http://fonts.googleapis.com/css?family=Open+Sans:400,300italic,800,300,400italic,600,600italic,700,700italic,800italic' rel='stylesheet' type='text/css' />
@ -89,7 +92,6 @@
nextEffect : 'none' nextEffect : 'none'
<?php if ($isEink) echo ", openEffect : 'none', closeEffect : 'none', helpers : {overlay : null}"; ?> <?php if ($isEink) echo ", openEffect : 'none', closeEffect : 'none', helpers : {overlay : null}"; ?>
}); });
<?php } ?>
$(".fancyabout").fancybox({ $(".fancyabout").fancybox({
'type' : 'ajax', 'type' : 'ajax',
@ -98,6 +100,7 @@
nextEffect : 'none' nextEffect : 'none'
<?php if ($isEink) echo ", openEffect : 'none', closeEffect : 'none', helpers : {overlay : null}"; ?> <?php if ($isEink) echo ", openEffect : 'none', closeEffect : 'none', helpers : {overlay : null}"; ?>
}); });
<?php } ?>
$(".headright").click(function(){ $(".headright").click(function(){
if ($("#tool").is(":hidden")) { if ($("#tool").is(":hidden")) {
@ -109,6 +112,7 @@
} }
}); });
<?php if ($page != Base::PAGE_BOOK_DETAIL) { ?>
$(".bookdetail").click(function(){ $(".bookdetail").click(function(){
var url = $(this).find("a").attr("href"); var url = $(this).find("a").attr("href");
<?php if ($config['cops_use_fancyapps'] == 0) { ?> <?php if ($config['cops_use_fancyapps'] == 0) { ?>
@ -124,6 +128,7 @@
<?php } ?> <?php } ?>
return false; return false;
}); });
<?php } ?>
}); });
<?php <?php
@ -148,25 +153,26 @@
</script> </script>
</head> </head>
<body> <body>
<div id="loading">
<p><img src="images/ajax-loader.gif" alt="waiting" /> Please Wait</p>
</div>
<div class="container"> <div class="container">
<header> <header>
<a class="headleft" href="<?php echo $_SERVER["SCRIPT_NAME"] ?>"> <a class="headleft" href="<?php echo $_SERVER["SCRIPT_NAME"]; if ($page != Base::PAGE_INDEX && !is_null ($database)) echo "?" . addURLParameter ("", DB, $database); ?>">
<img src="<?php echo getUrlWithVersion("images/home.png") ?>" alt="Home" /> <img src="<?php echo getUrlWithVersion("images/home.png") ?>" alt="<?php echo localize ("home.alternate") ?>" />
</a> </a>
<img class="headright" id="searchImage" src="<?php echo getUrlWithVersion("images/setting64.png") ?>" alt="Settings and menu" /> <img class="headright" id="searchImage" src="<?php echo getUrlWithVersion("images/setting64.png") ?>" alt="Settings and menu" />
<h1><?php echo htmlspecialchars ($currentPage->title) ?></h1> <h1><?php echo htmlspecialchars ($currentPage->title) ?></h1>
</header> </header>
<aside id="tool" <?php if ($withToolbar) echo 'style="display: none"' ?>> <aside id="tool" <?php if ($withToolbar) echo 'style="display: none"' ?>>
<div style="float: left; width: 60%"> <div style="float: left; width: 60%">
<form action="index.php?page=9" method="get"> <form action="index.php" method="get">
<div style="float: right"> <div style="float: right">
<input type="image" src="images/search32.png" alt="Search" /> <input type="image" src="images/search32.png" alt="<?php echo localize ("search.alternate") ?>" />
</div> </div>
<div class="stop"> <div class="stop">
<input type="hidden" name="current" value="<?php echo $page ?>" />
<input type="hidden" name="page" value="9" /> <input type="hidden" name="page" value="9" />
<?php if (!is_null ($database)) { ?>
<input type="hidden" name="<?php echo DB ?>" value="<?php echo $database ?>" />
<?php } ?>
<input type="text" name="query" /> <input type="text" name="query" />
</div> </div>
</form> </form>
@ -174,7 +180,7 @@
<?php if ($currentPage->containsBook ()) { ?> <?php if ($currentPage->containsBook ()) { ?>
<div style="float: right; width: 35%"> <div style="float: right; width: 35%">
<div style="float: right"> <div style="float: right">
<img id="sort" src="images/sort32.png" alt="Sort" /> <img id="sort" src="images/sort32.png" alt="<?php echo localize ("sort.alternate") ?>" />
</div> </div>
<div class="stop"> <div class="stop">
<select id="sortchoice"> <select id="sortchoice">
@ -184,8 +190,8 @@
<option value="sp"><?php echo localize("content.published") ?></option> <option value="sp"><?php echo localize("content.published") ?></option>
</select> </select>
<select id="sortorder"> <select id="sortorder">
<option value="asc">Asc</option> <option value="asc"><?php echo localize("search.sortorder.asc") ?></option>
<option value="desc">Desc</option> <option value="desc"><?php echo localize("search.sortorder.desc") ?></option>
</select> </select>
</div> </div>
</div> </div>
@ -193,14 +199,15 @@
</aside> </aside>
<div id="content" style="display: none;"></div> <div id="content" style="display: none;"></div>
<section> <section>
<?php <?php
if ($page == Base::PAGE_BOOK_DETAIL) if ($page == Base::PAGE_BOOK_DETAIL) {
{
include ("bookdetail.php"); include ("bookdetail.php");
} else if ($page == Base::PAGE_ABOUT) {
readfile ("about.xml");
} }
foreach ($currentPage->entryArray as $entry) { foreach ($currentPage->entryArray as $entry) {
if (get_class ($entry) != "EntryBook") { if (get_class ($entry) != "EntryBook") {
?> ?>
<article> <article>
<div class="frontpage"> <div class="frontpage">
<?php foreach ($entry->linkArray as $link) { if ($link->type != Link::OPDS_NAVIGATION_TYPE) { continue; } ?> <a href="<?php echo $link->hrefXhtml () ?>"> <?php foreach ($entry->linkArray as $link) { if ($link->type != Link::OPDS_NAVIGATION_TYPE) { continue; } ?> <a href="<?php echo $link->hrefXhtml () ?>">
@ -270,7 +277,9 @@
?> ?>
</section> </section>
<footer> <footer>
<a class="fancyabout" href="about.html"><img src="<?php echo getUrlWithVersion("images/info.png") ?>" alt="Home" /></a> <a class="fancyabout" href="<?php if ($config['cops_use_fancyapps'] == 1) { echo "about.xml"; } else { echo $_SERVER["SCRIPT_NAME"] . str_replace ("&", "&amp;", addURLParameter ("?page=16", DB, $database)); } "><img src="<?php echo getUrlWithVersion("images/info.png") ?>" alt="<?php echo localize ("about.title") ?>" /></a>
</a>
<?php <?php
if ($currentPage->isPaginated ()) { if ($currentPage->isPaginated ()) {
?> ?>
@ -279,7 +288,7 @@
<?php <?php
if (!is_null ($prevLink)) { if (!is_null ($prevLink)) {
?> ?>
<a href="<?php echo $prevLink->hrefXhtml () ?>" ><img src="<?php echo getUrlWithVersion("images/previous.png") ?>" alt="Previous" /></a> <a href="<?php echo $prevLink->hrefXhtml () ?>" ><img src="<?php echo getUrlWithVersion("images/previous.png") ?>" alt="<?php echo localize ("paging.previous.alternate") ?>" /></a>
<?php <?php
} }
?> ?>
@ -287,7 +296,7 @@
<?php <?php
if (!is_null ($nextLink)) { if (!is_null ($nextLink)) {
?> ?>
<a href="<?php echo $nextLink->hrefXhtml () ?>" ><img src="<?php echo getUrlWithVersion("images/next.png") ?>" alt="Next" /></a> <a href="<?php echo $nextLink->hrefXhtml () ?>" ><img src="<?php echo getUrlWithVersion("images/next.png") ?>" alt="<?php echo localize ("paging.next.alternate") ?>" /></a>
<?php <?php
} }
?> ?>

5
js/jquery-1.9.1.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -50,17 +50,17 @@
"tags.title":"Etiquetes", "tags.title":"Etiquetes",
"tags.categorized":"Llistat per categories de les {0} etiquetes", "tags.categorized":"Llistat per categories de les {0} etiquetes",
"tags.categorized.single":"Llistat per categories de la única etiqueta - molt útil ;)", "tags.categorized.single":"Llistat per categories de la única etiqueta - molt útil ;)",
"tags.alphabetical":"{0} etiquetes ordenades alfabèticament", "tags.alphabetical.many":"{0} etiquetes ordenades alfabèticament",
"tags.alphabetical.single":"Llistat alfabètic de la única etiqueta ;)", "tags.alphabetical.one":"Llistat alfabètic de la única etiqueta ;)",
"splitByLetter.tag.other":"Altres etiquetes", "splitByLetter.tag.other":"Altres etiquetes",
"authors.series.title":"Sèries", "authors.series.title":"Sèries",
"authors.title":"Autors", "authors.title":"Autors",
"authors.alphabetical":"{0} autors ordenats alfabèticament", "authors.alphabetical.many":"{0} autors ordenats alfabèticament",
"authors.alphabetical.single":"Índex s'un sol autor", "authors.alphabetical.one":"Índex s'un sol autor",
"splitByLetter.author.other":"Altres autors", "splitByLetter.author.other":"Altres autors",
"series.title":"Sèries", "series.title":"Sèries",
"series.alphabetical":"{0} sèries ordenades alfabèticament", "series.alphabetical.many":"{0} sèries ordenades alfabèticament",
"series.alphabetical.single":"Índex alfabètic d'una sola sèrie", "series.alphabetical.one":"Índex alfabètic d'una sola sèrie",
"splitByLetter.series.other":"Altres sèries", "splitByLetter.series.other":"Altres sèries",
"recent.title":"Els més recents", "recent.title":"Els més recents",
"recent.list":"{0} darrers títols incorporats", "recent.list":"{0} darrers títols incorporats",
@ -68,8 +68,8 @@
"rating.title":"Valoració", "rating.title":"Valoració",
"rating.summary":"{0}, agrupats per valoració", "rating.summary":"{0}, agrupats per valoració",
"allbooks.title":"Tots els llibres", "allbooks.title":"Tots els llibres",
"allbooks.alphabetical":"{0} llibres ordenats alfabèticament", "allbooks.alphabetical.many":"{0} llibres ordenats alfabèticament",
"allbooks.alphabetical.single":"Índex d'un sol llibre", "allbooks.alphabetical.one":"Índex d'un sol llibre",
"splitByLetter.book.other":"Altres llibres", "splitByLetter.book.other":"Altres llibres",
"main.title":"Biblioteca generada per Calibre", "main.title":"Biblioteca generada per Calibre",
"main.summary":"{0} ha catalogat {1}", "main.summary":"{0} ha catalogat {1}",
@ -83,7 +83,6 @@
"i18n.summarysection":"Resum", "i18n.summarysection":"Resum",
"i18n.dateGenerated":"Catàleg creat el {0}", "i18n.dateGenerated":"Catàleg creat el {0}",
"deeplevel.summary":"{0} per autors, etiquetes, etc.", "deeplevel.summary":"{0} per autors, etiquetes, etc.",
"about.title":"Documentació de Calibre2Opds",
"about.summary":"Notes d'ús", "about.summary":"Notes d'ús",
"usage.intro":"Les opcions provenen de l'arxiu de configuració present a: {0}", "usage.intro":"Les opcions provenen de l'arxiu de configuració present a: {0}",
"config.Language.label":"Idioma", "config.Language.label":"Idioma",

View file

@ -54,17 +54,17 @@
"tags.title":"Schlagwörter", "tags.title":"Schlagwörter",
"tags.categorized":"Index der {0} Schlagwörter nach Kategorien", "tags.categorized":"Index der {0} Schlagwörter nach Kategorien",
"tags.categorized.single":"Index des Schlagworts nach Kategorien - sehr nützlich ;)", "tags.categorized.single":"Index des Schlagworts nach Kategorien - sehr nützlich ;)",
"tags.alphabetical":"Alphabetischer Index der {0} Schlagwörter", "tags.alphabetical.many":"Alphabetischer Index der {0} Schlagwörter",
"tags.alphabetical.single":"Alphabetischer Index des Schlagworts ;)", "tags.alphabetical.one":"Alphabetischer Index des Schlagworts ;)",
"splitByLetter.tag.other":"Andere Schlagwörter", "splitByLetter.tag.other":"Andere Schlagwörter",
"authors.series.title":"Serien: {0}", "authors.series.title":"Serien: {0}",
"authors.title":"Autoren", "authors.title":"Autoren",
"authors.alphabetical":"Alphabetischer Index der {0} Autoren", "authors.alphabetical.many":"Alphabetischer Index der {0} Autoren",
"authors.alphabetical.single":"Alphabetischer Index des Autors - unglaublich nützlich ;)", "authors.alphabetical.one":"Alphabetischer Index des Autors - unglaublich nützlich ;)",
"splitByLetter.author.other":"Andere Autoren", "splitByLetter.author.other":"Andere Autoren",
"series.title":"Serien", "series.title":"Serien",
"series.alphabetical":"Alphabetischer Index der {0} Serien", "series.alphabetical.many":"Alphabetischer Index der {0} Serien",
"series.alphabetical.single":"Alphabetischer Index der Serie - äußerst nützlich ;)", "series.alphabetical.one":"Alphabetischer Index der Serie - äußerst nützlich ;)",
"splitByLetter.series.other":"Andere Serien", "splitByLetter.series.other":"Andere Serien",
"recent.title":"Neuzugänge", "recent.title":"Neuzugänge",
"recent.list":"{0} neue Bücher", "recent.list":"{0} neue Bücher",
@ -72,8 +72,8 @@
"rating.title":"Bewertung", "rating.title":"Bewertung",
"rating.summary":"{0}, gruppiert nach Bewertung", "rating.summary":"{0}, gruppiert nach Bewertung",
"allbooks.title":"Alle Bücher", "allbooks.title":"Alle Bücher",
"allbooks.alphabetical":"Alphabetischer Index der {0} Bücher", "allbooks.alphabetical.many":"Alphabetischer Index der {0} Bücher",
"allbooks.alphabetical.single":"Alphabetischer Index des einzigen Buchs - unverzichtbar ;)", "allbooks.alphabetical.one":"Alphabetischer Index des einzigen Buchs - unverzichtbar ;)",
"splitByLetter.book.other":"Andere Bücher", "splitByLetter.book.other":"Andere Bücher",
"main.title":"Calibre Bibliothek", "main.title":"Calibre Bibliothek",
"main.summary":"{0} hat {1} katalogisierte Bücher", "main.summary":"{0} hat {1} katalogisierte Bücher",
@ -100,7 +100,6 @@
"i18n.summarysection":"Zusammenfassung", "i18n.summarysection":"Zusammenfassung",
"i18n.dateGenerated":"Katalog erstellt am {0}", "i18n.dateGenerated":"Katalog erstellt am {0}",
"deeplevel.summary":"{0} aufgeschlüsselt nach Autoren, Schlagwörter, etc.", "deeplevel.summary":"{0} aufgeschlüsselt nach Autoren, Schlagwörter, etc.",
"about.title":"Calibre2Opds Dokumentation",
"about.summary":"Anmerkungen zur Verwendung von Calibre2Opds", "about.summary":"Anmerkungen zur Verwendung von Calibre2Opds",
"usage.intro":"Die Optionen werden der Konfigurationsdatei in {0} entnommen", "usage.intro":"Die Optionen werden der Konfigurationsdatei in {0} entnommen",
"config.Language.label":"Sprache", "config.Language.label":"Sprache",
@ -117,5 +116,8 @@
"intro.team.list5":"Jane Litte - Beta Tests und moralische Unterstützung", "intro.team.list5":"Jane Litte - Beta Tests und moralische Unterstützung",
"intro.thanks.1":"Speziellen Dank an Kb Sriram, der nicht nur Trook, eine exzellente und OPDS kompatible ", "intro.thanks.1":"Speziellen Dank an Kb Sriram, der nicht nur Trook, eine exzellente und OPDS kompatible ",
"intro.thanks.2":"Bibliotheksverwaltung programmierte, sondern auch einen Nook spendete!", "intro.thanks.2":"Bibliotheksverwaltung programmierte, sondern auch einen Nook spendete!",
"search.result":"Suchergebnis für",
"search.sortorder.asc":"Auf",
"search.sortorder.desc":"Ab",
"fin":"fin" "fin":"fin"
} }

View file

@ -57,17 +57,20 @@
"tags.title":"Tags", "tags.title":"Tags",
"tags.categorized":"Categorized index of the {0} tags", "tags.categorized":"Categorized index of the {0} tags",
"tags.categorized.single":"Categorized index of the single tag - very useful indeed ;)", "tags.categorized.single":"Categorized index of the single tag - very useful indeed ;)",
"tags.alphabetical":"Alphabetical index of the {0} tags", "tags.alphabetical.many":"Alphabetical index of the {0} tags",
"tags.alphabetical.single":"Alphabetical index of the single tag ;)", "tags.alphabetical.one":"Alphabetical index of the single tag - very useful indeed ;)",
"tags.alphabetical.none":"Alphabetical index of absolutely no tag - very useful indeed ;)",
"splitByLetter.tag.other":"Other tags", "splitByLetter.tag.other":"Other tags",
"authors.series.title":"Series: {0}", "authors.series.title":"Series: {0}",
"authors.title":"Authors", "authors.title":"Authors",
"authors.alphabetical":"Alphabetical index of the {0} authors", "authors.alphabetical.many":"Alphabetical index of the {0} authors",
"authors.alphabetical.single":"Alphabetical index of the single author - very useful indeed ;)", "authors.alphabetical.one":"Alphabetical index of the single author - very useful indeed ;)",
"authors.alphabetical.none":"Alphabetical index of absolutely no author - very useful indeed ;)",
"splitByLetter.author.other":"Other authors", "splitByLetter.author.other":"Other authors",
"series.title":"Series", "series.title":"Series",
"series.alphabetical":"Alphabetical index of the {0} series", "series.alphabetical.many":"Alphabetical index of the {0} series",
"series.alphabetical.single":"Alphabetical index of the single series - very useful indeed ;)", "series.alphabetical.one":"Alphabetical index of the single series - very useful indeed ;)",
"series.alphabetical.none":"Alphabetical index of absolutely no series - very useful indeed ;)",
"splitByLetter.series.other":"Other series", "splitByLetter.series.other":"Other series",
"recent.title":"Recent additions", "recent.title":"Recent additions",
"recent.list":"{0} most recent books", "recent.list":"{0} most recent books",
@ -75,8 +78,9 @@
"rating.title":"Rating", "rating.title":"Rating",
"rating.summary":"{0}, grouped by rating", "rating.summary":"{0}, grouped by rating",
"allbooks.title":"All books", "allbooks.title":"All books",
"allbooks.alphabetical":"Alphabetical index of the {0} books", "allbooks.alphabetical.many":"Alphabetical index of the {0} books",
"allbooks.alphabetical.single":"Alphabetical index of the single book - very useful indeed ;)", "allbooks.alphabetical.one":"Alphabetical index of the single book - very useful indeed ;)",
"allbooks.alphabetical.none":"Alphabetical index of absolutely no book - very useful indeed ;)",
"splitByLetter.book.other":"Other books", "splitByLetter.book.other":"Other books",
"main.title":"Calibre library", "main.title":"Calibre library",
"main.summary":"{0} has catalogued {1}", "main.summary":"{0} has catalogued {1}",
@ -103,7 +107,7 @@
"i18n.summarysection":"Description", "i18n.summarysection":"Description",
"i18n.dateGenerated":"Catalog generated on {0}", "i18n.dateGenerated":"Catalog generated on {0}",
"deeplevel.summary":"{0} broken up by authors, tags, etc. ", "deeplevel.summary":"{0} broken up by authors, tags, etc. ",
"about.title":"Calibre2Opds Documentation", "about.title":"About COPS",
"about.summary":"Notes on using Calibre2Opds", "about.summary":"Notes on using Calibre2Opds",
"usage.intro":"The options are taken from the configuration file located at {0}", "usage.intro":"The options are taken from the configuration file located at {0}",
"config.Language.label":"Language", "config.Language.label":"Language",
@ -120,5 +124,14 @@
"intro.team.list5":"Jane Litte - beta tester and moral support", "intro.team.list5":"Jane Litte - beta tester and moral support",
"intro.thanks.1":"Special thanks to Kb Sriram, who not only programmed Trook, an excellent and OPDS compatible ", "intro.thanks.1":"Special thanks to Kb Sriram, who not only programmed Trook, an excellent and OPDS compatible ",
"intro.thanks.2":"library manager for the Nook, but also was kind enough to donate a Nook !", "intro.thanks.2":"library manager for the Nook, but also was kind enough to donate a Nook !",
"search.result":"Search result for *{0}*",
"search.sortorder.asc":"Asc",
"search.sortorder.desc":"Desc",
"permalink.alternate":"Permalink",
"home.alternate":"Home",
"search.alternate":"Search",
"sort.alternate":"Sort",
"paging.next.alternate":"Next",
"paging.previous.alternate":"Previous",
"fin":"fin" "fin":"fin"
} }

View file

@ -50,17 +50,17 @@
"tags.title":"etiquetas", "tags.title":"etiquetas",
"tags.categorized":"Listado por categorias de las {0} etiquetas", "tags.categorized":"Listado por categorias de las {0} etiquetas",
"tags.categorized.single":"Listado por categorias de la unica etiqueta - muy util ;)", "tags.categorized.single":"Listado por categorias de la unica etiqueta - muy util ;)",
"tags.alphabetical":"Listado alfabético de las {0} etiquetas", "tags.alphabetical.many":"Listado alfabético de las {0} etiquetas",
"tags.alphabetical.single":"Listado Alfabético de la unica etiqueta ;)", "tags.alphabetical.one":"Listado Alfabético de la unica etiqueta ;)",
"splitByLetter.tag.other":"Otras etiquetas", "splitByLetter.tag.other":"Otras etiquetas",
"authors.series.title":"Series", "authors.series.title":"Series",
"authors.title":"Autores", "authors.title":"Autores",
"authors.alphabetical":"Indice alfabético de {0}", "authors.alphabetical.many":"Indice alfabético de {0}",
"authors.alphabetical.single":"Indice de un solo autor", "authors.alphabetical.one":"Indice de un solo autor",
"splitByLetter.author.other":"Otros Autores", "splitByLetter.author.other":"Otros Autores",
"series.title":"Series:", "series.title":"Series:",
"series.alphabetical":"Indice alfabético de {0}", "series.alphabetical.many":"Indice alfabético de {0}",
"series.alphabetical.single":"Indice de una sola serie", "series.alphabetical.one":"Indice de una sola serie",
"splitByLetter.series.other":"Otras series", "splitByLetter.series.other":"Otras series",
"recent.title":"Añadidos recientemente", "recent.title":"Añadidos recientemente",
"recent.list":"{0} libros más recientes", "recent.list":"{0} libros más recientes",
@ -68,8 +68,8 @@
"rating.title":"Valoración", "rating.title":"Valoración",
"rating.summary":"{0}, agrupados por valoración", "rating.summary":"{0}, agrupados por valoración",
"allbooks.title":"Todos los libros", "allbooks.title":"Todos los libros",
"allbooks.alphabetical":"Indice alfabético de {0} libros", "allbooks.alphabetical.many":"Indice alfabético de {0} libros",
"allbooks.alphabetical.single":"Indice de un solo ", "allbooks.alphabetical.one":"Indice de un solo ",
"splitByLetter.book.other":"Otros libros", "splitByLetter.book.other":"Otros libros",
"main.title":"Biblioteca generada de calibre", "main.title":"Biblioteca generada de calibre",
"main.summary":"{0} ha catalogado {1}", "main.summary":"{0} ha catalogado {1}",
@ -83,7 +83,6 @@
"i18n.summarysection":"Resumen", "i18n.summarysection":"Resumen",
"i18n.dateGenerated":"Catálogo creado el {0}", "i18n.dateGenerated":"Catálogo creado el {0}",
"deeplevel.summary":"{0} por autores, etiquetas, etc.", "deeplevel.summary":"{0} por autores, etiquetas, etc.",
"about.title":"Documentación de Calibre2Opds",
"about.summary":"Notas de Uso", "about.summary":"Notas de Uso",
"usage.intro":"Las opciones provienen del fichero de configuración presente en: {0}", "usage.intro":"Las opciones provienen del fichero de configuración presente en: {0}",
"config.Language.label":"Idioma", "config.Language.label":"Idioma",

View file

@ -55,17 +55,17 @@
"tags.title":"Étiquettes", "tags.title":"Étiquettes",
"tags.categorized":"Index ordonné des {0} étiquettes", "tags.categorized":"Index ordonné des {0} étiquettes",
"tags.categorized.single":"Index ordonné de la seule étiquette disponible", "tags.categorized.single":"Index ordonné de la seule étiquette disponible",
"tags.alphabetical":"Index alphabétique des {0} étiquettes", "tags.alphabetical.many":"Index alphabétique des {0} étiquettes",
"tags.alphabetical.single":"Index alphabétique de la seule étiquette ;)", "tags.alphabetical.one":"Index alphabétique de la seule étiquette ;)",
"splitByLetter.tag.other":"Autres étiquettes", "splitByLetter.tag.other":"Autres étiquettes",
"authors.series.title":"Collection: {0}", "authors.series.title":"Collection: {0}",
"authors.title":"Auteurs", "authors.title":"Auteurs",
"authors.alphabetical":"Index alphabétique des {0} auteurs", "authors.alphabetical.many":"Index alphabétique des {0} auteurs",
"authors.alphabetical.single":"Index alphabétique du seul auteur ;)", "authors.alphabetical.one":"Index alphabétique du seul auteur ;)",
"splitByLetter.author.other":"Autres auteurs", "splitByLetter.author.other":"Autres auteurs",
"series.title":"Collections", "series.title":"Collections",
"series.alphabetical":"Index alphabétique de {0} collections", "series.alphabetical.many":"Index alphabétique de {0} collections",
"series.alphabetical.single":"Index alphabétique de la seule collection ;)", "series.alphabetical.one":"Index alphabétique de la seule collection ;)",
"splitByLetter.series.other":"Autres collections", "splitByLetter.series.other":"Autres collections",
"recent.title":"Ajouts récents", "recent.title":"Ajouts récents",
"recent.list":"{0} livres les plus récents", "recent.list":"{0} livres les plus récents",
@ -73,8 +73,8 @@
"rating.title":"Appréciations", "rating.title":"Appréciations",
"rating.summary":"{0}, par appréciation", "rating.summary":"{0}, par appréciation",
"allbooks.title":"Tous les livres", "allbooks.title":"Tous les livres",
"allbooks.alphabetical":"Index alphabétique des {0} livres", "allbooks.alphabetical.many":"Index alphabétique des {0} livres",
"allbooks.alphabetical.single":"Index alphabétique du seul livre ;)", "allbooks.alphabetical.one":"Index alphabétique du seul livre ;)",
"splitByLetter.book.other":"Autres livres", "splitByLetter.book.other":"Autres livres",
"main.title":"Bibliothèque gérée par Calibre", "main.title":"Bibliothèque gérée par Calibre",
"main.summary":"{0} a catalogué {1}", "main.summary":"{0} a catalogué {1}",
@ -89,7 +89,7 @@
"i18n.summarysection":"Résumé", "i18n.summarysection":"Résumé",
"i18n.dateGenerated":"Catalogue généré le {0}", "i18n.dateGenerated":"Catalogue généré le {0}",
"deeplevel.summary":"{0} par auteur, étiquette, etc.", "deeplevel.summary":"{0} par auteur, étiquette, etc.",
"about.title":"Documentation de Calibre2Opds", "about.title":"A propos de COPS",
"about.summary":"Notes d'utilisation", "about.summary":"Notes d'utilisation",
"usage.intro":"Les options sont tirées du fichier de configuration qui se trouve ici : {0}", "usage.intro":"Les options sont tirées du fichier de configuration qui se trouve ici : {0}",
"config.Language.label":"Langue", "config.Language.label":"Langue",
@ -105,5 +105,14 @@
"intro.team.list5":"Jane Litte - beta testeuse et soutien moral", "intro.team.list5":"Jane Litte - beta testeuse et soutien moral",
"intro.thanks.1":"Remerciements particuliers à Kb Sriram, qui est l'auteur de Trook, un excellent", "intro.thanks.1":"Remerciements particuliers à Kb Sriram, qui est l'auteur de Trook, un excellent",
"intro.thanks.2":"gestionnaire de bibliothèque pour Nook, et a m'a fait cadeau d'un Nook !", "intro.thanks.2":"gestionnaire de bibliothèque pour Nook, et a m'a fait cadeau d'un Nook !",
"search.result":"Résultats pour *{0}*",
"search.sortorder.asc":"Crois.",
"search.sortorder.desc":"Décrois.",
"permalink.alternate":"Permalien",
"home.alternate":"Accueil",
"search.alternate":"Rechercher",
"sort.alternate":"Trier",
"paging.next.alternate":"Suivant",
"paging.previous.alternate":"Précédent",
"fin":"fin" "fin":"fin"
} }

View file

@ -51,17 +51,17 @@
"tags.title":"Argomenti", "tags.title":"Argomenti",
"tags.categorized":"Indice ordinato di {0} argomenti", "tags.categorized":"Indice ordinato di {0} argomenti",
"tags.categorized.single":"Indice ordinato del solo argomento disponibile", "tags.categorized.single":"Indice ordinato del solo argomento disponibile",
"tags.alphabetical":"Indice alfabetico di {0} argomenti", "tags.alphabetical.many":"Indice alfabetico di {0} argomenti",
"tags.alphabetical.single":"Indice alfabetico del solo argomento ;)", "tags.alphabetical.one":"Indice alfabetico del solo argomento ;)",
"splitByLetter.tag.other":"Altri argomenti", "splitByLetter.tag.other":"Altri argomenti",
"authors.series.title":"Collane: {0}", "authors.series.title":"Collane: {0}",
"authors.title":"Autori", "authors.title":"Autori",
"authors.alphabetical":"Indice alfabetico di {0} autori", "authors.alphabetical.many":"Indice alfabetico di {0} autori",
"authors.alphabetical.single":"Indice alfabetico di un solo autore ;)", "authors.alphabetical.one":"Indice alfabetico di un solo autore ;)",
"splitByLetter.author.other":"Altri autori", "splitByLetter.author.other":"Altri autori",
"series.title":"Collane", "series.title":"Collane",
"series.alphabetical":"Indice alfabetico di {0} collane", "series.alphabetical.many":"Indice alfabetico di {0} collane",
"series.alphabetical.single":"Indice alfabetico di una sola collana ;)", "series.alphabetical.one":"Indice alfabetico di una sola collana ;)",
"splitByLetter.series.other":"Altre collane", "splitByLetter.series.other":"Altre collane",
"recent.title":"Ultime aggiunte", "recent.title":"Ultime aggiunte",
"recent.list":" I {0} libri più recenti", "recent.list":" I {0} libri più recenti",
@ -69,8 +69,8 @@
"rating.title":"Valutazioni", "rating.title":"Valutazioni",
"rating.summary":"{0}, per valutazioni", "rating.summary":"{0}, per valutazioni",
"allbooks.title":"Tutti i libri", "allbooks.title":"Tutti i libri",
"allbooks.alphabetical":"Indice alfabetico di {0} libri", "allbooks.alphabetical.many":"Indice alfabetico di {0} libri",
"allbooks.alphabetical.single":"Indice alfabetico di un solo libro ;)", "allbooks.alphabetical.one":"Indice alfabetico di un solo libro ;)",
"splitByLetter.book.other":"Altri libri", "splitByLetter.book.other":"Altri libri",
"main.title":"Biblioteca generata da Calibre", "main.title":"Biblioteca generata da Calibre",
"main.summary":"{0} ha catalogato {1}", "main.summary":"{0} ha catalogato {1}",
@ -84,7 +84,6 @@
"i18n.summarysection":"Riassunto", "i18n.summarysection":"Riassunto",
"i18n.dateGenerated":"Catalogo generato il {0}", "i18n.dateGenerated":"Catalogo generato il {0}",
"deeplevel.summary":"{0} par autore, etichetta, ecc.", "deeplevel.summary":"{0} par autore, etichetta, ecc.",
"about.title":"Documentazione di Calibre2Opds",
"about.summary":"Note d'utilizzo", "about.summary":"Note d'utilizzo",
"usage.intro":"Le opzioni sono prese dal file di configuraziones che si trova qui: {0}", "usage.intro":"Le opzioni sono prese dal file di configuraziones che si trova qui: {0}",
"config.Language.label":"Lingua", "config.Language.label":"Lingua",

View file

@ -56,17 +56,17 @@
"tags.title":"Tags", "tags.title":"Tags",
"tags.categorized":"Gecategorizeerde index van {0} tags", "tags.categorized":"Gecategorizeerde index van {0} tags",
"tags.categorized.single":"Gecategorizeerde index van 1 tag - Erg handig ;)", "tags.categorized.single":"Gecategorizeerde index van 1 tag - Erg handig ;)",
"tags.alphabetical":"Alfabetische index van {0} tags", "tags.alphabetical.many":"Alfabetische index van {0} tags",
"tags.alphabetical.single":"Alfabetische index van 1 tag ;)", "tags.alphabetical.one":"Alfabetische index van 1 tag ;)",
"splitByLetter.tag.other":"Andere tags", "splitByLetter.tag.other":"Andere tags",
"authors.series.title":"Series: {0}", "authors.series.title":"Series: {0}",
"authors.title":"Auteurs", "authors.title":"Auteurs",
"authors.alphabetical":"Alfabetische index van {0} auteurs", "authors.alphabetical.many":"Alfabetische index van {0} auteurs",
"authors.alphabetical.single":"Alfabetische index van 1 auteur - Erg handig ;)", "authors.alphabetical.one":"Alfabetische index van 1 auteur - Erg handig ;)",
"splitByLetter.author.other":"Andere auteurs", "splitByLetter.author.other":"Andere auteurs",
"series.title":"Series", "series.title":"Series",
"series.alphabetical":"Alfabetische index van {0} series", "series.alphabetical.many":"Alfabetische index van {0} series",
"series.alphabetical.single":"Alfabetische index van 1 serie - Erg handig ;)", "series.alphabetical.one":"Alfabetische index van 1 serie - Erg handig ;)",
"splitByLetter.series.other":"Andere series", "splitByLetter.series.other":"Andere series",
"recent.title":"Recent toegevoegd", "recent.title":"Recent toegevoegd",
"recent.list":"{0} meest recente boeken", "recent.list":"{0} meest recente boeken",
@ -74,8 +74,8 @@
"rating.title":"Rating", "rating.title":"Rating",
"rating.summary":"{0}, gegroepeerd per rating", "rating.summary":"{0}, gegroepeerd per rating",
"allbooks.title":"Alle boeken", "allbooks.title":"Alle boeken",
"allbooks.alphabetical":"Alfabetische index van {0} boeken", "allbooks.alphabetical.many":"Alfabetische index van {0} boeken",
"allbooks.alphabetical.single":"Alfabetische index van 1 boek", "allbooks.alphabetical.one":"Alfabetische index van 1 boek",
"splitByLetter.book.other":"Andere boeken", "splitByLetter.book.other":"Andere boeken",
"main.title":"Calibre bibliotheek", "main.title":"Calibre bibliotheek",
"main.summary":"{0} heeft gecatalogiseerd {1}", "main.summary":"{0} heeft gecatalogiseerd {1}",
@ -102,7 +102,6 @@
"i18n.summarysection":"Omschrijving", "i18n.summarysection":"Omschrijving",
"i18n.dateGenerated":"Catalogus gegenereerd op {0}", "i18n.dateGenerated":"Catalogus gegenereerd op {0}",
"deeplevel.summary":"{0} uitgesplitst naar auteurs, tags, etc. ", "deeplevel.summary":"{0} uitgesplitst naar auteurs, tags, etc. ",
"about.title":"Calibre2Opds Documentatie",
"about.summary":"Notities hoe Calibre2Opds te gebruiken", "about.summary":"Notities hoe Calibre2Opds te gebruiken",
"usage.intro":"De opties worden uit het configuratie bestand {0} gebruikt", "usage.intro":"De opties worden uit het configuratie bestand {0} gebruikt",
"config.Language.label":"Taal", "config.Language.label":"Taal",

View file

@ -53,17 +53,17 @@
"tags.title":"Тэги", "tags.title":"Тэги",
"tags.categorized":"Категорированный указатель для {0} тэгов", "tags.categorized":"Категорированный указатель для {0} тэгов",
"tags.categorized.single":"Категорированный указатель для одного тэга - действительно очень полезно ;)", "tags.categorized.single":"Категорированный указатель для одного тэга - действительно очень полезно ;)",
"tags.alphabetical":"Алфавитный указатель для {0} тэгов", "tags.alphabetical.many":"Алфавитный указатель для {0} тэгов",
"tags.alphabetical.single":"Алфавитный указатель для одного тэга ;)", "tags.alphabetical.one":"Алфавитный указатель для одного тэга ;)",
"splitByLetter.tag.other":"Другие тэги", "splitByLetter.tag.other":"Другие тэги",
"authors.series.title":"Серии: {0}", "authors.series.title":"Серии: {0}",
"authors.title":"Авторы", "authors.title":"Авторы",
"authors.alphabetical":"Алфавитный указатель для {0} авторов", "authors.alphabetical.many":"Алфавитный указатель для {0} авторов",
"authors.alphabetical.single":"Алфавитный указатель для одного автора - действительно очень полезно ;)", "authors.alphabetical.one":"Алфавитный указатель для одного автора - действительно очень полезно ;)",
"splitByLetter.author.other":"Другие авторы", "splitByLetter.author.other":"Другие авторы",
"series.title":"Серии", "series.title":"Серии",
"series.alphabetical":"Алфавитный указатель для {0} серий", "series.alphabetical.many":"Алфавитный указатель для {0} серий",
"series.alphabetical.single":"Алфавитный указатель для одной серии - действительно очень полезно ;)", "series.alphabetical.one":"Алфавитный указатель для одной серии - действительно очень полезно ;)",
"splitByLetter.series.other":"Другие серии", "splitByLetter.series.other":"Другие серии",
"recent.title":"Недавние поступления", "recent.title":"Недавние поступления",
"recent.list":"{0} недавно поступивших(ие) книг(и)", "recent.list":"{0} недавно поступивших(ие) книг(и)",
@ -71,8 +71,8 @@
"rating.title":"Рейтинг", "rating.title":"Рейтинг",
"rating.summary":"{0}, сгруппировано по рейтингу", "rating.summary":"{0}, сгруппировано по рейтингу",
"allbooks.title":"Все книги", "allbooks.title":"Все книги",
"allbooks.alphabetical":"Алфавитный указатель всех {0} книг", "allbooks.alphabetical.many":"Алфавитный указатель всех {0} книг",
"allbooks.alphabetical.single":"Алфавитный указатель одной книги - действительно очень полезно ;)", "allbooks.alphabetical.one":"Алфавитный указатель одной книги - действительно очень полезно ;)",
"splitByLetter.book.other":"Другие книги", "splitByLetter.book.other":"Другие книги",
"main.title":"Библиотека Calibre", "main.title":"Библиотека Calibre",
"main.summary":"{0} каталогизировано {1}", "main.summary":"{0} каталогизировано {1}",
@ -86,7 +86,6 @@
"i18n.summarysection":"Краткое содержание", "i18n.summarysection":"Краткое содержание",
"i18n.dateGenerated":"Каталог создан {0}", "i18n.dateGenerated":"Каталог создан {0}",
"deeplevel.summary":"{0} разбито по авторам, тэгам и т.д.", "deeplevel.summary":"{0} разбито по авторам, тэгам и т.д.",
"about.title":"Документация Calibre2Opds",
"about.summary":"Примечания по использованию Calibre2Opds", "about.summary":"Примечания по использованию Calibre2Opds",
"usage.intro":"Эта опция взята из файла конфигурации, расположенного в {0}", "usage.intro":"Эта опция взята из файла конфигурации, расположенного в {0}",
"config.Language.label":"Язык", "config.Language.label":"Язык",

137
lang/Localization_zh.json Normal file
View file

@ -0,0 +1,137 @@
{
"boolean.no":"否",
"boolean.yes":"是",
"splitByLetter.letter":"{0} 以 {1} 开头",
"home.title":"目录",
"link.fullentry":"全部条目",
"title.nextpage":"下一页 ({0} of {1})",
"title.lastpage":"最后一页",
"title.numberOfPages":"{0} (共 {1} 页)",
"pubdate.title":"出版时间",
"bookword.title":"书名",
"bookword.none":"没有书籍",
"bookword.one":"1 本书籍",
"bookword.many":"{0} 本书籍",
"authorword.title":"作者",
"authorword.none":"未知",
"authorword.one":"1 位作者",
"authorword.many":"{0} 位作者",
"taglevelword.title":"Tag levels",
"taglevelword.none":"No tag level",
"taglevelword.one":"1 tag level",
"taglevelword.many":"{0} tag levels",
"seriesword.title":"系列",
"seriesword.none":"没有系列",
"seriesword.one":"1 个系列",
"seriesword.many":"{0} 系列",
"tagword.title":"标签",
"tagword.none":"没有标签",
"tagword.one":"1 个标签",
"tagword.many":"{0} 标签",
"content.tags":"标签:",
"content.series":"系列:",
"content.series.data":"{0} 系列的第 {0} 本",
"content.publisher":"出版社:",
"content.published":"出版时间",
"content.added":"添加了: ",
"content.modified":"修改了:",
"content.publisher.data":"由 {0} 出版于 {1}",
"content.summary":"概要",
"bookentry.series":"Book {0} in the {1} series",
"bookentry.author":"{0} 由作者 {1}",
"bookentry.tags":"{0} 在标签 {1}",
"bookentry.ratings":"{0} 评分 {1}",
"bookentry.goodreads":"Goodreads 上的这本书",
"bookentry.goodreads.review":"在 Goodreads上评论这本书",
"bookentry.goodreads.author":"{0} 在 Goodreads",
"bookentry.wikipedia":"维基百科上的这本书",
"bookentry.wikipedia.author":"{0} 在维基百科上",
"bookentry.librarything":"LibraryThing 上的这本书",
"bookentry.librarything.author":"{0} 在 LibraryThing",
"bookentry.amazon":"Amazon上的这本书",
"bookentry.amazon.author":"{0} 在 Amazon",
"bookentry.isfdb.author":"{0} 在 ISFDB",
"bookentry.download":"下载这本书 {0}",
"bookentry.rated":"{0} {1}",
"bookentry.fullentrylink":"全部条目",
"tags.title":"标签",
"tags.categorized":"Categorized index of the {0} tags",
"tags.categorized.single":"Categorized index of the single tag - very useful indeed ;)",
"tags.alphabetical.many":"{0} 个标签的字母索引",
"tags.alphabetical.one":"Alphabetical index of the single tag - very useful indeed ;)",
"tags.alphabetical.none":"Alphabetical index of absolutely no tag - very useful indeed ;)",
"splitByLetter.tag.other":"其他标签",
"authors.series.title":"系列: {0}",
"authors.title":"作者",
"authors.alphabetical.many":"{0} 位作者的字母索引",
"authors.alphabetical.one":"Alphabetical index of the single author - very useful indeed ;)",
"authors.alphabetical.none":"Alphabetical index of absolutely no author - very useful indeed ;)",
"splitByLetter.author.other":"其他作者",
"series.title":"系列",
"series.alphabetical.many":"{0} 个系列的字母索引",
"series.alphabetical.one":"Alphabetical index of the single series - very useful indeed ;)",
"series.alphabetical.none":"Alphabetical index of absolutely no series - very useful indeed ;)",
"splitByLetter.series.other":"其他系列",
"recent.title":"最近添加",
"recent.list":"{0} 本最近添加的书",
"recent.list.single":"Most recent single book - very useful indeed ;)",
"rating.title":"Rating",
"rating.summary":"{0}, 根据评分分组",
"allbooks.title":"所有书籍",
"allbooks.alphabetical.many":"{0} 本书籍的字母索引",
"allbooks.alphabetical.one":"Alphabetical index of the single book - very useful indeed ;)",
"allbooks.alphabetical.none":"Alphabetical index of absolutely no book - very useful indeed ;)",
"splitByLetter.book.other":"其他书籍",
"main.title":"Calibre 书架",
"main.summary":"{0} has catalogued {1}",
"startup.newhome":"Default configuration folder home redirected to {0}",
"startup.redirectfound":".redirect file found in {0}",
"startup.redirectreadfail":"... failure reading .redirect file",
"startup.redirectnotfound":"... unable to find redirect folder {0}",
"startup.redirectabandoned":"... so redirect abandoned",
"startup.redirecting":"redirecting home folder to {0}",
"startup.configusing":"Using configuration folder {0}",
"startup.folderuserhome":"Try configuration folder in user home folder {0}",
"startup.foldertilde":"Try configuration folder from tilde folder {0}",
"startup.folderjar":"Try configuration folder from .jar location {0}",
"startup.foldernotexist":"... but specified folder does not exist",
"i18n.and":"和",
"i18n.downloads":"下载,链接和其他目录 ",
"i18n.links":"链接和其他目录",
"i18n.coversection":"封面",
"i18n.downloadfile":"下载文件",
"i18n.downloadsection":"下载",
"i18n.relatedsection":"相关目录",
"i18n.linksection":"外部链接",
"i18n.backToMain":"返回目录主页",
"i18n.summarysection":"描述",
"i18n.dateGenerated":"目录生成于 {0}",
"deeplevel.summary":"{0} broken up by authors, tags, etc. ",
"about.title":"关于COPS",
"about.summary":"关于Calibre2Opds的说明",
"usage.intro":"选项从此配置文件生成 {0}",
"config.Language.label":"语言",
"config.Language.description":"此项设置将会改变程序使用的语言 ; 请使用ISO标准语言代码 (例如 EN, FR, DE...)",
"config.Language.possible":"可能的选项 : {0}",
"intro.goal":"从你的 Calibre 数据库生成 OPDS 和 HTML 目录",
"intro.wiki.title":"项目主页 : ",
"intro.wiki.url":"http://calibre2opds.com",
"intro.team.title":"项目人员 :",
"intro.team.list1":"David Pierron - main programmer",
"intro.team.list2":"Dave Walker - guru, features manager and tester extraordinaire",
"intro.team.list3":"Farid Soussi - css and html guru",
"intro.team.list4":"Douglas Steele - programmer",
"intro.team.list5":"Jane Litte - beta tester and moral support",
"intro.thanks.1":"Special thanks to Kb Sriram, who not only programmed Trook, an excellent and OPDS compatible ",
"intro.thanks.2":"library manager for the Nook, but also was kind enough to donate a Nook !",
"search.result":"*{0}* 的搜索结果",
"search.sortorder.asc":"升序",
"search.sortorder.desc":"降序",
"permalink.alternate":"永久链接",
"home.alternate":"首页",
"search.alternate":"搜索",
"sort.alternate":"排序",
"paging.next.alternate":"下一页",
"paging.previous.alternate":"上一页",
"fin":"fin"
}

View file

Before

Width:  |  Height:  |  Size: 43 B

After

Width:  |  Height:  |  Size: 43 B

View file

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View file

Before

Width:  |  Height:  |  Size: 1,003 B

After

Width:  |  Height:  |  Size: 1,003 B

View file

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -1,4 +1,4 @@
/*! fancyBox v2.1.3 fancyapps.com | fancyapps.com/fancybox/#license */ /*! fancyBox v2.1.4 fancyapps.com | fancyapps.com/fancybox/#license */
.fancybox-wrap, .fancybox-wrap,
.fancybox-skin, .fancybox-skin,
.fancybox-outer, .fancybox-outer,

File diff suppressed because one or more lines are too long

View file

@ -17,3 +17,6 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
All code created or modified by Sébastien Lucas <sebastien@slucas.fr> is licensed
under GPL 2 (http://www.gnu.org/licenses/gpl.html).

View file

@ -3,15 +3,18 @@
* PHP EPub Meta library * PHP EPub Meta library
* *
* @author Andreas Gohr <andi@splitbrain.org> * @author Andreas Gohr <andi@splitbrain.org>
* @author Sébastien Lucas <sebastien@slucas.fr>
*/ */
require_once('tbszip.php'); require_once(realpath( dirname( __FILE__ ) ) . '/tbszip.php');
define ("METADATA_FILE", "META-INF/container.xml"); define ("METADATA_FILE", "META-INF/container.xml");
class EPub { class EPub {
public $xml; //FIXME change to protected, later public $xml; //FIXME change to protected, later
public $toc;
protected $xpath; protected $xpath;
protected $toc_xpath;
protected $file; protected $file;
protected $meta; protected $meta;
protected $zip; protected $zip;
@ -64,6 +67,26 @@ class EPub {
$this->xml->formatOutput = true; $this->xml->formatOutput = true;
$this->xpath = new EPubDOMXPath($this->xml); $this->xpath = new EPubDOMXPath($this->xml);
} }
public function initSpineComponent ()
{
$spine = $this->xpath->query('//opf:spine')->item(0);
$tocid = $spine->getAttribute('toc');
$tochref = $this->xpath->query("//opf:manifest/opf:item[@id='$tocid']")->item(0)->attr('href');
$tocpath = dirname($this->meta).'/'.$tochref;
// read epub toc
if (!$this->zip->FileExists($tocpath)) {
throw new Exception ("Unable to find " . $tocpath);
}
$data = $this->zip->FileRead($tocpath);
$this->toc = new DOMDocument();
$this->toc->registerNodeClass('DOMElement','EPubDOMElement');
$this->toc->loadXML($data);
$this->toc_xpath = new EPubDOMXPath($this->toc);
$rootNamespace = $this->toc->lookupNamespaceUri($this->toc->namespaceURI);
$this->toc_xpath->registerNamespace('x', $rootNamespace);
}
/** /**
* file name getter * file name getter
@ -81,13 +104,24 @@ class EPub {
$this->zip->Close (); $this->zip->Close ();
} }
/**
* Remove iTunes files
*/
public function cleanITunesCrap () {
if ($this->zip->FileExists("iTunesMetadata.plist")) {
$this->zip->FileReplace ("iTunesMetadata.plist", false);
}
if ($this->zip->FileExists("iTunesArtwork")) {
$this->zip->FileReplace ("iTunesArtwork", false);
}
}
/** /**
* Writes back all meta data changes * Writes back all meta data changes
* TODO update
*/ */
public function save(){ public function save(){
$this->download (); $this->download ();
$zip->close(); $this->zip->close();
} }
/** /**
@ -102,7 +136,57 @@ class EPub {
} }
if ($file) $this->zip->Flush(TBSZIP_DOWNLOAD, $file); if ($file) $this->zip->Flush(TBSZIP_DOWNLOAD, $file);
} }
/**
* Get the components list as an array
*/
public function components(){
$spine = array();
$nodes = $this->xpath->query('//opf:spine/opf:itemref');
foreach($nodes as $node){
$idref = $node->getAttribute('idref');
$spine[] = $this->xpath->query("//opf:manifest/opf:item[@id='$idref']")->item(0)->getAttribute('href');
}
return $spine;
}
/**
* Get the component content
*/
public function component($comp) {
$path = dirname($this->meta).'/'.$comp;
if (!$this->zip->FileExists($path)) {
throw new Exception ("Unable to find " . $path);
}
$data = $this->zip->FileRead($path);
$data = preg_replace ("/src=[\"']([\w\/\.]*?)[\"']/", "src='epubfs.php?comp=$1'", $data);
$data = preg_replace ("/href=[\"']([\w\/\.]*?)[\"']/", "href='epubfs.php?comp=$1'", $data);
return $data;
}
/**
* Get the component content type
*/
public function componentContentType($comp) {
return $this->xpath->query("//opf:manifest/opf:item[@href='$comp']")->item(0)->getAttribute('media-type');
}
/**
* Get the Epub content (TOC) as an array
*
* For each chapter there is a "title" and a "src"
*/
public function contents(){
$contents = array();
$nodes = $this->toc_xpath->query('//x:ncx/x:navMap/x:navPoint');
foreach($nodes as $node){
$title = $this->toc_xpath->query('x:navLabel/x:text', $node)->item(0)->nodeValue;
$src = $this->toc_xpath->query('x:content', $node)->item(0)->attr('src');
$contents[] = array("title" => $title, "src" => $src);
}
return $contents;
}
/** /**
@ -413,7 +497,6 @@ class EPub {
} }
} }
public function Cover2($path=false, $mime=false){ public function Cover2($path=false, $mime=false){
$hascover = true; $hascover = true;
$item = $this->getCoverItem (); $item = $this->getCoverItem ();
@ -423,6 +506,7 @@ class EPub {
$mime = $item->attr('opf:media-type'); $mime = $item->attr('opf:media-type');
$this->coverpath = $item->attr('opf:href'); $this->coverpath = $item->attr('opf:href');
$this->coverpath = dirname('/'.$this->meta).'/'.$this->coverpath; // image path is relative to meta file $this->coverpath = dirname('/'.$this->meta).'/'.$this->coverpath; // image path is relative to meta file
$this->coverpath = ltrim($this->coverpath,'\\');
$this->coverpath = ltrim($this->coverpath,'/'); $this->coverpath = ltrim($this->coverpath,'/');
} }
@ -441,18 +525,6 @@ class EPub {
} }
if (!$hascover) return $this->no_cover(); if (!$hascover) return $this->no_cover();
$zip = new ZipArchive();
if(!@$zip->open($this->file)){
throw new Exception('Failed to read epub file');
}
$data = $zip->getFromName($this->coverpath);
return array(
'mime' => $mime,
'data' => $data,
'found' => $this->coverpath
);
} }
/** /**

View file

@ -1,7 +1,8 @@
<?php <?php
/* /*
TbsZip version 2.11 (2012-02-14) TbsZip version 2.12
Date : 2013-03-16
Author : Skrol29 (email: http://www.tinybutstrong.com/onlyyou.html) Author : Skrol29 (email: http://www.tinybutstrong.com/onlyyou.html)
Licence : LGPL Licence : LGPL
This class is independent from any other classes and has been originally created for the OpenTbs plug-in This class is independent from any other classes and has been originally created for the OpenTbs plug-in
@ -36,7 +37,7 @@ class clsTbsZip {
$this->CdPos = $this->CdInfo['p_cd']; $this->CdPos = $this->CdInfo['p_cd'];
} }
function Open($ArchFile) { function Open($ArchFile, $UseIncludePath=false) {
// Open the zip archive // Open the zip archive
if (!isset($this->Meth8Ok)) $this->__construct(); // for PHP 4 compatibility if (!isset($this->Meth8Ok)) $this->__construct(); // for PHP 4 compatibility
$this->Close(); // close handle and init info $this->Close(); // close handle and init info
@ -44,7 +45,7 @@ class clsTbsZip {
$this->ArchFile = $ArchFile; $this->ArchFile = $ArchFile;
$this->ArchIsNew = false; $this->ArchIsNew = false;
// open the file // open the file
$this->ArchHnd = fopen($ArchFile, 'rb'); $this->ArchHnd = fopen($ArchFile, 'rb', $UseIncludePath);
$ok = !($this->ArchHnd===false); $ok = !($this->ArchHnd===false);
if ($ok) $ok = $this->CentralDirRead(); if ($ok) $ok = $this->CentralDirRead();
return $ok; return $ok;
@ -89,7 +90,7 @@ class clsTbsZip {
$cd_pos = -22; $cd_pos = -22;
$this->_MoveTo($cd_pos, SEEK_END); $this->_MoveTo($cd_pos, SEEK_END);
$b = $this->_ReadData(4); $b = $this->_ReadData(4);
if ($b!==$cd_info) return $this->RaiseError('The footer of the Central Directory is not found.'); if ($b!==$cd_info) return $this->RaiseError('The End of Central Rirectory Record is not found.');
$this->CdEndPos = ftell($this->ArchHnd) - 4; $this->CdEndPos = ftell($this->ArchHnd) - 4;
$this->CdInfo = $this->CentralDirRead_End($cd_info); $this->CdInfo = $this->CentralDirRead_End($cd_info);
@ -97,8 +98,8 @@ class clsTbsZip {
$this->CdFileNbr = $this->CdInfo['file_nbr_curr']; $this->CdFileNbr = $this->CdInfo['file_nbr_curr'];
$this->CdPos = $this->CdInfo['p_cd']; $this->CdPos = $this->CdInfo['p_cd'];
if ($this->CdFileNbr<=0) return $this->RaiseError('No file found in the Central Directory.'); if ($this->CdFileNbr<=0) return $this->RaiseError('No header found in the Central Directory.');
if ($this->CdPos<=0) return $this->RaiseError('No position found for the Central Directory listing.'); if ($this->CdPos<=0) return $this->RaiseError('No position found for the Central Directory.');
$this->_MoveTo($this->CdPos); $this->_MoveTo($this->CdPos);
for ($i=0;$i<$this->CdFileNbr;$i++) { for ($i=0;$i<$this->CdFileNbr;$i++) {
@ -114,13 +115,13 @@ class clsTbsZip {
function CentralDirRead_End($cd_info) { function CentralDirRead_End($cd_info) {
$b = $cd_info.$this->_ReadData(18); $b = $cd_info.$this->_ReadData(18);
$x = array(); $x = array();
$x['disk_num_curr'] = $this->_GetDec($b,4,2); // number of this disk $x['disk_num_curr'] = $this->_GetDec($b,4,2); // number of this disk
$x['disk_num_cd'] = $this->_GetDec($b,6,2); // number of the disk with the start of the central directory $x['disk_num_cd'] = $this->_GetDec($b,6,2); // number of the disk with the start of the central directory
$x['file_nbr_curr'] = $this->_GetDec($b,8,2); // total number of entries in the central directory on this disk $x['file_nbr_curr'] = $this->_GetDec($b,8,2); // total number of entries in the central directory on this disk
$x['file_nbr_tot'] = $this->_GetDec($b,10,2); // total number of entries in the central directory $x['file_nbr_tot'] = $this->_GetDec($b,10,2); // total number of entries in the central directory
$x['l_cd'] = $this->_GetDec($b,12,4); // size of the central directory $x['l_cd'] = $this->_GetDec($b,12,4); // size of the central directory
$x['p_cd'] = $this->_GetDec($b,16,4); // offset of start of central directory with respect to the starting disk number $x['p_cd'] = $this->_GetDec($b,16,4); // position of start of central directory with respect to the starting disk number
$x['l_comm'] = $this->_GetDec($b,20,2); // .ZIP file comment length $x['l_comm'] = $this->_GetDec($b,20,2); // .ZIP file comment length
$x['v_comm'] = $this->_ReadData($x['l_comm']); // .ZIP file comment $x['v_comm'] = $this->_ReadData($x['l_comm']); // .ZIP file comment
$x['bin'] = $b.$x['v_comm']; $x['bin'] = $b.$x['v_comm'];
return $x; return $x;
@ -131,7 +132,7 @@ class clsTbsZip {
$b = $this->_ReadData(46); $b = $this->_ReadData(46);
$x = $this->_GetHex($b,0,4); $x = $this->_GetHex($b,0,4);
if ($x!=='h:02014b50') return $this->RaiseError('Signature of file information not found in the Central Directory in position '.(ftell($this->ArchHnd)-46).' for file #'.$idx.'.'); if ($x!=='h:02014b50') return $this->RaiseError("Signature of Central Directory Header #".$idx." (file information) expected but not found at position ".$this->_TxtPos(ftell($this->ArchHnd) - 46).".");
$x = array(); $x = array();
$x['vers_used'] = $this->_GetDec($b,4,2); $x['vers_used'] = $this->_GetDec($b,4,2);
@ -169,36 +170,56 @@ class clsTbsZip {
$this->DisplayError = true; $this->DisplayError = true;
echo "<br />\r\n";
echo "------------------<br/>\r\n";
echo "Central Directory:<br/>\r\n";
echo "------------------<br/>\r\n";
print_r($this->CdInfo);
echo "<br />\r\n";
echo "-----------------------------------<br/>\r\n";
echo "File List in the Central Directory:<br/>\r\n";
echo "-----------------------------------<br/>\r\n";
print_r($this->CdFileLst);
if ($FileHeaders) { if ($FileHeaders) {
echo "<br/>\r\n"; // Calculations first in order to have error messages before other information
echo "------------------------------<br/>\r\n";
echo "File List in the Data Section:<br/>\r\n";
echo "------------------------------<br/>\r\n";
$idx = 0; $idx = 0;
$pos = 0; $pos = 0;
$pos_stop = $this->CdInfo['p_cd'];
$this->_MoveTo($pos); $this->_MoveTo($pos);
while ($ok = $this->_ReadFile($idx,false)) { while ( ($pos<$pos_stop) && ($ok = $this->_ReadFile($idx,false)) ) {
$this->VisFileLst[$idx]['debug_pos'] = $pos; $this->VisFileLst[$idx]['p_this_header (debug_mode only)'] = $pos;
$pos = ftell($this->ArchHnd); $pos = ftell($this->ArchHnd);
$idx++; $idx++;
} }
print_r($this->VisFileLst); }
$nl = "\r\n";
echo "<pre>";
echo "-------------------------------".$nl;
echo "End of Central Directory record".$nl;
echo "-------------------------------".$nl;
print_r($this->DebugArray($this->CdInfo));
echo $nl;
echo "-------------------------".$nl;
echo "Central Directory headers".$nl;
echo "-------------------------".$nl;
print_r($this->DebugArray($this->CdFileLst));
if ($FileHeaders) {
echo $nl;
echo "------------------".$nl;
echo "Local File headers".$nl;
echo "------------------".$nl;
print_r($this->DebugArray($this->VisFileLst));
} }
echo "</pre>";
} }
function DebugArray($arr) {
foreach ($arr as $k=>$v) {
if (is_array($v)) {
$arr[$k] = $this->DebugArray($v);
} elseif (substr($k,0,2)=='p_') {
$arr[$k] = $this->_TxtPos($v);
}
}
return $arr;
}
function FileExists($NameOrIdx) { function FileExists($NameOrIdx) {
return ($this->FileGetIdx($NameOrIdx)!==false); return ($this->FileGetIdx($NameOrIdx)!==false);
} }
@ -272,9 +293,9 @@ class clsTbsZip {
// read the file header (and maybe the data ) in the archive, assuming the cursor in at a new file position // read the file header (and maybe the data ) in the archive, assuming the cursor in at a new file position
$b = $this->_ReadData(30); $b = $this->_ReadData(30);
$x = $this->_GetHex($b,0,4); $x = $this->_GetHex($b,0,4);
if ($x!=='h:04034b50') return $this->RaiseError('Signature of file information not found in the Data Section in position '.(ftell($this->ArchHnd)-30).' for file #'.$idx.'.'); if ($x!=='h:04034b50') return $this->RaiseError("Signature of Local File Header #".$idx." (data section) expected but not found at position ".$this->_TxtPos(ftell($this->ArchHnd)-30).".");
$x = array(); $x = array();
$x['vers'] = $this->_GetDec($b,4,2); $x['vers'] = $this->_GetDec($b,4,2);
@ -293,15 +314,20 @@ class clsTbsZip {
$x['bin'] = $b.$x['v_name'].$x['v_fields']; $x['bin'] = $b.$x['v_name'].$x['v_fields'];
// Read Data // Read Data
$len_cd = $this->CdFileLst[$idx]['l_data_c']; if (isset($this->CdFileLst[$idx])) {
if ($x['l_data_c']==0) { $len_cd = $this->CdFileLst[$idx]['l_data_c'];
// Sometimes, the size is not specified in the local information. if ($x['l_data_c']==0) {
$len = $len_cd; // Sometimes, the size is not specified in the local information.
$len = $len_cd;
} else {
$len = $x['l_data_c'];
if ($len!=$len_cd) {
//echo "TbsZip Warning: Local information for file #".$idx." says len=".$len.", while Central Directory says len=".$len_cd.".";
}
}
} else { } else {
$len = $x['l_data_c']; $len = $x['l_data_c'];
if ($len!=$len_cd) { if ($len==0) $this->RaiseError("File Data #".$idx." cannt be read because no length is specified in the Local File Header and its Central Directory information has not been found.");
//echo "TbsZip Warning: Local information for file #".$idx." says len=".$len.", while Central Directory says len=".$len_cd.".";
}
} }
if ($ReadData) { if ($ReadData) {
@ -309,16 +335,25 @@ class clsTbsZip {
} else { } else {
$this->_MoveTo($len, SEEK_CUR); $this->_MoveTo($len, SEEK_CUR);
} }
// Description information // Description information
$desc_ok = ($x['purp'][2+3]=='1'); $desc_ok = ($x['purp'][2+3]=='1');
if ($desc_ok) { if ($desc_ok) {
$b = $this->_ReadData(16); $b = $this->_ReadData(12);
$x['desc_bin'] = $b; $s = $this->_GetHex($b,0,4);
$x['desc_sign'] = $this->_GetHex($b,0,4); // not specified in the documentation sign=h:08074b50 $d = 0;
$x['desc_crc32'] = $this->_GetDec($b,4,4); // the specification says the signature may or may not be present
$x['desc_l_data_c'] = $this->_GetDec($b,8,4); if ($s=='h:08074b50') {
$x['desc_l_data_u'] = $this->_GetDec($b,12,4); $b .= $this->_ReadData(4);
$d = 4;
$x['desc_bin'] = $b;
$x['desc_sign'] = $s;
} else {
$x['desc_bin'] = $b;
}
$x['desc_crc32'] = $this->_GetDec($b,0+$d,4);
$x['desc_l_data_c'] = $this->_GetDec($b,4+$d,4);
$x['desc_l_data_u'] = $this->_GetDec($b,8+$d,4);
} }
// Save file info without the data // Save file info without the data
@ -441,9 +476,10 @@ class clsTbsZip {
if ($ReplInfo['meth']!==false) $this->_PutDec($b1, $ReplInfo['meth'], 8, 2); // meth if ($ReplInfo['meth']!==false) $this->_PutDec($b1, $ReplInfo['meth'], 8, 2); // meth
// prepare the bottom description if the zipped file, if any // prepare the bottom description if the zipped file, if any
if ($b2!=='') { if ($b2!=='') {
$this->_PutDec($b2, $ReplInfo['crc32'], 4, 4); // crc32 $d = (strlen($b2)==16) ? 4 : 0; // offset because of the signature if any
$this->_PutDec($b2, $ReplInfo['len_c'], 8, 4); // l_data_c $this->_PutDec($b2, $ReplInfo['crc32'], $d+0, 4); // crc32
$this->_PutDec($b2, $ReplInfo['len_u'], 12, 4); // l_data_u $this->_PutDec($b2, $ReplInfo['len_c'], $d+4, 4); // l_data_c
$this->_PutDec($b2, $ReplInfo['len_u'], $d+8, 4); // l_data_u
} }
// output data // output data
$this->OutputFromString($b1.$ReplInfo['data'].$b2); $this->OutputFromString($b1.$ReplInfo['data'].$b2);
@ -501,7 +537,7 @@ class clsTbsZip {
$ArchPos += $old_cd_len; $ArchPos += $old_cd_len;
$DeltaCdLen = $DeltaCdLen + strlen($b2) - $old_cd_len; $DeltaCdLen = $DeltaCdLen + strlen($b2) - $old_cd_len;
// Output until Central Directory footer // Output until "end of central directory record"
if ($this->ArchHnd!==false) $this->OutputFromArch($ArchPos, $this->CdEndPos); // ArchHnd is false if CreateNew() has been called if ($this->ArchHnd!==false) $this->OutputFromArch($ArchPos, $this->CdEndPos); // ArchHnd is false if CreateNew() has been called
// Output file information of the Central Directory for added files // Output file information of the Central Directory for added files
@ -514,7 +550,7 @@ class clsTbsZip {
$DeltaCdLen += strlen($b2); $DeltaCdLen += strlen($b2);
} }
// Output Central Directory footer // Output "end of central directory record"
$b2 = $this->CdInfo['bin']; $b2 = $this->CdInfo['bin'];
$DelNbr = count($DelLst); $DelNbr = count($DelLst);
if ( ($AddNbr>0) or ($DelNbr>0) ) { if ( ($AddNbr>0) or ($DelNbr>0) ) {
@ -708,6 +744,11 @@ class clsTbsZip {
return $y.'-'.str_pad($m,2,'0',STR_PAD_LEFT).'-'.str_pad($d,2,'0',STR_PAD_LEFT).' '.str_pad($h,2,'0',STR_PAD_LEFT).':'.str_pad($i,2,'0',STR_PAD_LEFT).':'.str_pad($s,2,'0',STR_PAD_LEFT); return $y.'-'.str_pad($m,2,'0',STR_PAD_LEFT).'-'.str_pad($d,2,'0',STR_PAD_LEFT).' '.str_pad($h,2,'0',STR_PAD_LEFT).':'.str_pad($i,2,'0',STR_PAD_LEFT).':'.str_pad($s,2,'0',STR_PAD_LEFT);
} }
function _TxtPos($pos) {
// Return the human readable position in both decimal and hexa
return $pos." (h:".dechex($pos).")";
}
function _DataOuputAddedFile($Idx, $PosLoc) { function _DataOuputAddedFile($Idx, $PosLoc) {
$Ref =& $this->AddInfo[$Idx]; $Ref =& $this->AddInfo[$Idx];

View file

@ -30,7 +30,7 @@ class Serie extends Base {
public static function getCount() { public static function getCount() {
$nSeries = parent::getDb ()->query('select count(*) from series')->fetchColumn(); $nSeries = parent::getDb ()->query('select count(*) from series')->fetchColumn();
$entry = new Entry (localize("series.title"), self::ALL_SERIES_ID, $entry = new Entry (localize("series.title"), self::ALL_SERIES_ID,
str_format (localize("series.alphabetical"), $nSeries), "text", str_format (localize("series.alphabetical", $nSeries), $nSeries), "text",
array ( new LinkNavigation ("?page=".parent::PAGE_ALL_SERIES))); array ( new LinkNavigation ("?page=".parent::PAGE_ALL_SERIES)));
return $entry; return $entry;
} }

View file

@ -224,21 +224,6 @@ display: block;
overflow: hidden; overflow: hidden;
} }
#loading
{
display:none;
position:fixed;
left:0;
top:0;
width:100%;
height:100%;
background-color: #ccc;
filter: alpha(opacity=70);
opacity: 0.70;
text-align: center;
padding-top: 120px;
}
/* ============================================================================= /* =============================================================================
Mediaquerie stuff goes here Mediaquerie stuff goes here
========================================================================== */ ========================================================================== */

View file

@ -30,7 +30,7 @@ class tag extends Base {
public static function getCount() { public static function getCount() {
$nTags = parent::getDb ()->query('select count(*) from tags')->fetchColumn(); $nTags = parent::getDb ()->query('select count(*) from tags')->fetchColumn();
$entry = new Entry (localize("tags.title"), self::ALL_TAGS_ID, $entry = new Entry (localize("tags.title"), self::ALL_TAGS_ID,
str_format (localize("tags.alphabetical"), $nTags), "text", str_format (localize("tags.alphabetical", $nTags), $nTags), "text",
array ( new LinkNavigation ("?page=".parent::PAGE_ALL_TAGS))); array ( new LinkNavigation ("?page=".parent::PAGE_ALL_TAGS)));
return $entry; return $entry;
} }