Add search ability to OPDS feed

This commit is contained in:
Alex Cabal 2020-06-19 16:20:40 -05:00
parent c6988a87d7
commit 86f3adca36
7 changed files with 94 additions and 6 deletions

View file

@ -159,9 +159,9 @@ Define domain standardebooks.org
RewriteRule ^(.+)$ $1.php [QSA]
# End PHP-FPM configuration
# Received: /filename and /filename.xml exists in filesystem; Result: rewrite to /filename.xml and end request
# Received: /filename and /filename.xml exists in filesystem; Result: rewrite to /filename.xml
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME}.xml -f
RewriteRule (.*) $1.xml [L]
RewriteRule (.*) $1.xml
# Remove trailing slashes
RewriteRule ^/(.+?)/$ /$1 [R=301,L]
@ -219,6 +219,10 @@ Define domain standardebooks.org
RewriteCond %{REQUEST_FILENAME} !^/ebooks/.+?/dist/.+$
RewriteCond %{REQUEST_FILENAME} !^/ebooks/.+?/src/.+$
RewriteRule ^/ebooks/([^\.]+?)$ /ebooks/ebook.php?url-path=$1
# If we ask for /opds/all?query=xyz, rewrite that to the search page.
RewriteCond %{QUERY_STRING} ^query=
RewriteRule ^/opds/all.xml$ /opds/search.php [QSA]
</VirtualHost>
<VirtualHost *:80>

View file

@ -158,9 +158,9 @@ Define domain standardebooks.test
RewriteRule ^(.+)$ $1.php [QSA]
# End PHP-FPM configuration
# Received: /filename and /filename.xml exists in filesystem; Result: rewrite to /filename.xml and end request
# Received: /filename and /filename.xml exists in filesystem; Result: rewrite to /filename.xml
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME}.xml -f
RewriteRule (.*) $1.xml [L]
RewriteRule (.*) $1.xml
# Remove trailing slashes
RewriteRule ^/(.+?)/$ /$1 [R=301,L]
@ -218,4 +218,8 @@ Define domain standardebooks.test
RewriteCond %{REQUEST_FILENAME} !^/ebooks/.+?/dist/.+$
RewriteCond %{REQUEST_FILENAME} !^/ebooks/.+?/src/.+$
RewriteRule ^/ebooks/([^\.]+?)$ /ebooks/ebook.php?url-path=$1
# If we ask for /opds/all?query=xyz, rewrite that to the search page.
RewriteCond %{QUERY_STRING} ^query=
RewriteRule ^/opds/all.xml$ /opds/search.php [QSA]
</VirtualHost>

View file

@ -6,13 +6,15 @@ class Contributor{
public $WikipediaUrl;
public $MarcRole;
public $FullName;
public $NacoafUrl;
public function __construct(string $name, string $sortName = null, string $fullName = null, string $wikipediaUrl = null, string $marcRole = null){
public function __construct(string $name, string $sortName = null, string $fullName = null, string $wikipediaUrl = null, string $marcRole = null, string $nacoafUrl = null){
$this->Name = str_replace('\'', '', $name);
$this->UrlName = Formatter::MakeUrlSafe($name);
$this->SortName = $sortName;
$this->FullName = $fullName;
$this->WikipediaUrl = $wikipediaUrl;
$this->MarcRole = $marcRole;
$this->NacoafUrl = $nacoafUrl;
}
}

View file

@ -50,6 +50,7 @@ class Ebook{
public $ContributorsHtml;
public $TitleWithCreditsHtml = '';
public $Timestamp;
public $ModifiedTimestamp;
public function __construct(string $wwwFilesystemPath){
// First, construct a source repo path from our WWW filesystem path.
@ -162,6 +163,11 @@ class Ebook{
$this->Timestamp = new DateTime((string)$date[0]);
}
$modifiedDate = $xml->xpath('/package/metadata/meta[@property="dcterms:modified"]');
if($modifiedDate !== false && sizeof($modifiedDate) > 0){
$this->ModifiedTimestamp = new DateTime((string)$modifiedDate[0]);
}
// Get SE tags
foreach($xml->xpath('/package/metadata/meta[@property="se:subject"]') ?: [] as $tag){
$this->Tags[] = new Tag($tag);
@ -222,7 +228,8 @@ class Ebook{
(string)$contributor,
$this->NullIfEmpty($xml->xpath('/package/metadata/meta[@property="file-as"][@refines="#' . $id . '"]')),
$this->NullIfEmpty($xml->xpath('/package/metadata/meta[@property="se:name.person.full-name"][@refines="#' . $id . '"]')),
$this->NullIfEmpty($xml->xpath('/package/metadata/meta[@property="se:url.encyclopedia.wikipedia"][@refines="#' . $id . '"]'))
$this->NullIfEmpty($xml->xpath('/package/metadata/meta[@property="se:url.encyclopedia.wikipedia"][@refines="#' . $id . '"]')),
$this->NullIfEmpty($xml->xpath('/package/metadata/meta[@property="se:url.authority.nacoaf"][@refines="#' . $id . '"]'))
);
// A display-sequence of 0 indicates that we don't want to process this contributor

View file

@ -42,6 +42,7 @@ print("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
<link href="<?= $webUrl ?>/opds/all" rel="self" type="application/atom+xml;profile=opds-catalog;kind=acquisition"/>
<link href="<?= $webUrl ?>/opds" rel="start" type="application/atom+xml;profile=opds-catalog;kind=navigation"/>
<link href="<?= $webUrl ?>/opds/all" rel="crawlable" type="application/atom+xml;profile=opds-catalog;kind=acquisition"/>
<link href="<?= $webUrl ?>/ebooks/opensearch" rel="search" type="application/opensearchdescription+xml" />
<title>All Standard Ebooks</title>
<subtitle>Free and liberated ebooks, carefully produced for the true book lover.</subtitle>
<icon><?= $webUrl ?>/images/logo.png</icon>

31
templates/OpdsEntry.php Normal file
View file

@ -0,0 +1,31 @@
<entry>
<id><?= SITE_URL . $ebook->Url ?></id>
<title><?= $ebook->Title ?></title>
<? foreach($ebook->Authors as $author){ ?>
<author>
<name><?= $author->Name ?></name>
<? if($author->WikipediaUrl !== null){ ?><uri><?= $author->WikipediaUrl ?></uri><? } ?>
<? if($author->FullName !== null){ ?><schema:alternateName><?= $author->FullName ?></schema:alternateName><? } ?>
<? if($author->NacoafUrl !== null){ ?><schema:sameAs><?= $author->NacoafUrl ?></schema:sameAs><? } ?>
</author>
<? } ?>
<published><?= $ebook->Timestamp->format('Y-m-d\TH:i:s\Z') ?></published>
<dc:issued><?= $ebook->Timestamp->format('Y-m-d\TH:i:s\Z') ?></dc:issued>
<dc:language><?= $ebook->Language ?></dc:language>
<dc:publisher>Standard Ebooks</dc:publisher>
<? foreach($ebook->Sources as $source){ ?>
<dc:source><?= $source->Url ?></dc:source>
<? } ?>
<rights>Public domain in the United States; original content released to the public domain via the Creative Commons CC0 1.0 Universal Public Domain Dedication</rights>
<summary type="text"><?= htmlspecialchars($ebook->Description, ENT_QUOTES, 'UTF-8') ?></summary>
<content type="text/html"><?= $ebook->LongDescription ?></content>
<? foreach($ebook->LocTags as $subject){ ?>
<category scheme="http://purl.org/dc/terms/LCSH" term="<?= htmlspecialchars($subject, ENT_QUOTES, 'UTF-8') ?>"/>
<? } ?>
<link href="<?= $ebook->Url ?>/dist/cover.jpg" rel="http://opds-spec.org/image" type="image/jpeg"/>
<link href="<?= $ebook->Url ?>/dist/cover-thumbnail.jpg" rel="http://opds-spec.org/image/thumbnail" type="image/jpeg"/>
<link href="<?= $ebook->EpubUrl ?>" rel="http://opds-spec.org/acquisition/open-access" type="application/epub+zip" title="Recommended compatible epub"/>
<link href="<?= $ebook->Epub3Url ?>" rel="http://opds-spec.org/acquisition/open-access" type="application/epub+zip" title="epub"/>
<link href="<?= $ebook->KepubUrl ?>" rel="http://opds-spec.org/acquisition/open-access" type="application/kepub+zip" title="Kobo Kepub epub"/>
<link href="<?= $ebook->Azw3Url ?>" rel="http://opds-spec.org/acquisition/open-access" type="application/x-mobipocket-ebook" title="Amazon Kindle azw3"/>
</entry>

39
www/opds/search.php Normal file
View file

@ -0,0 +1,39 @@
<?
require_once('Core.php');
$now = new DateTime('now', new DateTimeZone('UTC'));
try{
$query = HttpInput::GetString('query', false);
if($query !== null){
$ebooks = Library::Search($query);
}
}
catch(\Exception $ex){
http_response_code(500);
include(WEB_ROOT . '/404.php');
exit();
}
header('Content-type: text/xml');
print("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:schema="http://schema.org/" xmlns:fh="http://purl.org/syndication/history/1.0">
<id>https://standardebooks.org/opds/all</id>
<link href="/opds/all?query=<?= urlencode($query) ?>" rel="self" type="application/atom+xml;profile=opds-catalog"/>
<link href="/ebooks/ebooks?query=doyle" rel="alternate" type="text/html"/>
<link href="https://standardebooks.org/opds" rel="start" type="application/atom+xml;profile=opds-catalog;kind=navigation"/>
<link href="https://standardebooks.org/opds/all" rel="crawlable" type="application/atom+xml;profile=opds-catalog;kind=acquisition"/>
<link href="https://standardebooks.org/ebooks/opensearch" rel="search" type="application/opensearchdescription+xml" />
<title>Standard Ebooks OPDS Search Results</title>
<subtitle>Free and liberated ebooks, carefully produced for the true book lover.</subtitle>
<icon>https://standardebooks.org/images/logo.png</icon>
<updated><?= $now->Format('Y-m-d\TH:i:s\Z') ?></updated>
<author>
<name>Standard Ebooks</name>
<uri>https://standardebooks.org</uri>
</author>
<? foreach($ebooks as $ebook){ ?>
<?= Template::OpdsEntry(['ebook' => $ebook]) ?>
<? } ?>
</feed>