Skip to content

Commit

Permalink
Move feeds under new /feeds root
Browse files Browse the repository at this point in the history
  • Loading branch information
acabal committed Jun 24, 2022
1 parent ee54550 commit c109c56
Show file tree
Hide file tree
Showing 22 changed files with 136 additions and 99 deletions.
12 changes: 6 additions & 6 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
ebooks/*
www/ebooks/*
www/images/covers/*
www/opds/*.xml
www/opds/subjects/*.xml
www/rss/*.xml
www/rss/subjects/*.xml
www/atom/*.xml
www/atom/subjects/*.xml
www/feeds/opds/*.xml
www/feeds/opds/subjects/*.xml
www/feeds/rss/*.xml
www/feeds/rss/subjects/*.xml
www/feeds/atom/*.xml
www/feeds/atom/subjects/*.xml
vendor/
composer.lock
.vagrant/
Expand Down
3 changes: 0 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,6 @@ sudo ln -s /standardebooks.org/web/config/php/fpm/standardebooks.test.ini /etc/p
sudo ln -s /standardebooks.org/web/config/php/fpm/standardebooks.test.ini /etc/php/*/fpm/conf.d/
sudo ln -s /standardebooks.org/web/config/php/fpm/standardebooks.test.conf /etc/php/*/fpm/pool.d/
sudo systemctl restart "php*-fpm.service"

# Download the OPDS index template
wget -O /standardebooks.org/web/www/opds/index.xml https://standardebooks.org/opds
```

If everything went well you should now be able to open your web browser and visit `https://standardebooks.test/`. However, you won’t see any ebooks if you visit `https://standardebooks.test/ebooks/`. To install some ebooks, first you have to clone their source from GitHub, then deploy them to your local website using the `./scripts/deploy-ebook-to-www` script:
Expand Down
21 changes: 12 additions & 9 deletions config/apache/standardebooks.org.conf
Original file line number Diff line number Diff line change
Expand Up @@ -102,22 +102,22 @@ Define webroot /standardebooks.org/web
Header set Content-Type "text/plain"
</location>

# application/xml allows the page to be displayed in a browser. application/atom+xml will cause it to be downloaded.
<Location ~ ^/opds.+?$>
<Location ~ ^/feeds/opds>
DirectoryIndex index.xml
Header set Content-Type "application/xml"
</location>

# application/xml allows the page to be displayed in a browser and the encoding to be
# text/xml allows the page to be displayed in a browser and the encoding to be
# determined from the document and not the HTTP headers. application/rss+xml will cause it to be downloaded.
<Location ~ ^/(rss|atom)/.*$>
Header set Content-Type "application/xml"
</Location>
<Directory ~ ${webroot}/www/feeds/>
<Files ~ (\.xml|search\.php)$>
Header set Content-Type "text/xml; charset=utf-8"
</Files>
</Directory>

# Enable HTTP CORS so that browser-based readers like Readium can access opds and ebooks
# Allow fonts for newsletter emails
# See https://github.com/standardebooks/tools/issues/2
<Location ~ /(ebooks|opds|fonts)>
<Location ~ /(ebooks|feeds/opds|fonts)>
Header set Access-Control-Allow-Origin "*"
</Location>

Expand Down Expand Up @@ -250,7 +250,10 @@ Define webroot /standardebooks.org/web

# 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]
RewriteRule ^/feeds/opds/all.xml$ /feeds/opds/search.php [QSA]

# Rewrite old links to feeds
RewriteRule ^/(opds|rss|atom)(.*)$ /feeds/$1$2 [R=301,L]

# Newsletter
RewriteRule ^/newsletter$ /newsletter/subscribers/new.php
Expand Down
21 changes: 12 additions & 9 deletions config/apache/standardebooks.test.conf
Original file line number Diff line number Diff line change
Expand Up @@ -101,22 +101,22 @@ Define webroot /standardebooks.org/web
Header set Content-Type "text/plain"
</location>

# application/xml allows the page to be displayed in a browser. application/atom+xml will cause it to be downloaded.
<Location ~ ^/opds.+?$>
<Location ~ ^/feeds/opds>
DirectoryIndex index.xml
Header set Content-Type "application/xml"
</location>

# application/xml allows the page to be displayed in a browser and the encoding to be
# text/xml allows the page to be displayed in a browser and the encoding to be
# determined from the document and not the HTTP headers. application/rss+xml will cause it to be downloaded.
<Location ~ ^/(rss|atom)/.*$>
Header set Content-Type "application/xml"
</Location>
<Directory ~ ${webroot}/www/feeds/>
<Files ~ (\.xml|search\.php)$>
Header set Content-Type "text/xml; charset=utf-8"
</Files>
</Directory>

# Enable HTTP CORS so that browser-based readers like Readium can access opds and ebooks
# Allow fonts for newsletter emails
# See https://github.com/standardebooks/tools/issues/2
<Location ~ /(ebooks|opds|fonts)>
<Location ~ /(ebooks|feeds/opds|fonts)>
Header set Access-Control-Allow-Origin "*"
</Location>

Expand Down Expand Up @@ -249,7 +249,10 @@ Define webroot /standardebooks.org/web

# 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]
RewriteRule ^/feeds/opds/all.xml$ /feeds/opds/search.php [QSA]

# Rewrite old links to feeds
RewriteRule ^/(opds|rss|atom)(.*)$ /feeds/$1$2 [R=301,L]

# Newsletter
RewriteRule ^/newsletter$ /newsletter/subscribers/new.php
Expand Down
2 changes: 1 addition & 1 deletion lib/AtomFeed.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public function __construct(string $title, string $subtitle, string $url, string
parent::__construct($title, $url, $path, $entries);
$this->Subtitle = $subtitle;
$this->Id = $url;
$this->Stylesheet = '/atom/style';
$this->Stylesheet = '/feeds/atom/style';
}

protected function GetXmlString(): string{
Expand Down
2 changes: 1 addition & 1 deletion lib/OpdsFeed.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class OpdsFeed extends AtomFeed{
public function __construct(string $title, string $subtitle, string $url, string $path, array $entries, ?OpdsNavigationFeed $parent){
parent::__construct($title, $subtitle, $url, $path, $entries);
$this->Parent = $parent;
$this->Stylesheet = '/opds/style';
$this->Stylesheet = '/feeds/opds/style';
}

protected function SaveUpdatedTimestamp(string $entryId, DateTime $updatedTimestamp): void{
Expand Down
2 changes: 1 addition & 1 deletion lib/RssFeed.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ class RssFeed extends Feed{
public function __construct(string $title, string $description, string $url, string $path, array $entries){
parent::__construct($title, $url, $path, $entries);
$this->Description = $description;
$this->Stylesheet = '/rss/style';
$this->Stylesheet = '/feeds/rss/style';
}

protected function GetXmlString(): string{
Expand Down
42 changes: 21 additions & 21 deletions scripts/generate-feeds
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,16 @@ $subjects = [];
$ebooksBySubject = [];
$ebooksPerNewestEbooksFeed = 30;

if(!is_dir(WEB_ROOT . '/opds/subjects')){
mkdir(WEB_ROOT . '/opds/subjects');
if(!is_dir(WEB_ROOT . '/feeds/opds/subjects')){
mkdir(WEB_ROOT . '/feeds/opds/subjects');
}

if(!is_dir(WEB_ROOT . '/rss/subjects')){
mkdir(WEB_ROOT . '/rss/subjects');
if(!is_dir(WEB_ROOT . '/feeds/rss/subjects')){
mkdir(WEB_ROOT . '/feeds/rss/subjects');
}

if(!is_dir(WEB_ROOT . '/atom/subjects')){
mkdir(WEB_ROOT . '/atom/subjects');
if(!is_dir(WEB_ROOT . '/feeds/atom/subjects')){
mkdir(WEB_ROOT . '/feeds/atom/subjects');
}

// Iterate over all ebooks to build the various feeds
Expand Down Expand Up @@ -86,86 +86,86 @@ $opdsRootEntries = [
new OpdsNavigationEntry(
'Newest ' . number_format($ebooksPerNewestEbooksFeed) . ' Standard Ebooks',
'The ' . number_format($ebooksPerNewestEbooksFeed) . ' latest Standard Ebooks, most-recently-released first.',
'/opds/new-releases',
'/feeds/opds/new-releases',
$now,
'http://opds-spec.org/sort/new',
'acquisition'
),
new OpdsNavigationEntry(
'Standard Ebooks by Subject',
'Browse Standard Ebooks by subject.',
'/opds/subjects',
'/feeds/opds/subjects',
$now,
'subsection',
'navigation'),
new OpdsNavigationEntry(
'All Standard Ebooks',
'All Standard Ebooks, most-recently-updated first. This is a Complete Acquisition Feed as defined in OPDS 1.2 §2.5.',
'/opds/all',
'/feeds/opds/all',
$now,
'http://opds-spec.org/crawlable',
'acquisition')
];

$opdsRoot = new OpdsNavigationFeed('Standard Ebooks', 'The navigation root for the Standard Ebooks OPDS feed.', '/opds', WEB_ROOT . '/opds/index.xml', $opdsRootEntries, null);
$opdsRoot = new OpdsNavigationFeed('Standard Ebooks', 'The navigation root for the Standard Ebooks OPDS feed.', '/feeds/opds', WEB_ROOT . '/feeds/opds/index.xml', $opdsRootEntries, null);
SaveFeed($opdsRoot, $force, $now);

// Create the subjects navigation document
sort($subjects);
$subjectNavigationEntries = [];
foreach($subjects as $subject){
$subjectNavigationEntries[] = new OpdsNavigationEntry($subject, 'Standard Ebooks tagged with “' . strtolower($subject) . ',” most-recently-released first.', '/opds/subjects/' . Formatter::MakeUrlSafe($subject), $now, 'subsection', 'navigation');
$subjectNavigationEntries[] = new OpdsNavigationEntry($subject, 'Standard Ebooks tagged with “' . strtolower($subject) . ',” most-recently-released first.', '/feeds/opds/subjects/' . Formatter::MakeUrlSafe($subject), $now, 'subsection', 'navigation');
}
$subjectsFeed = new OpdsNavigationFeed('Standard Ebooks by Subject', 'Browse Standard Ebooks by subject.', '/opds/subjects', WEB_ROOT . '/opds/subjects/index.xml', $subjectNavigationEntries, $opdsRoot);
$subjectsFeed = new OpdsNavigationFeed('Standard Ebooks by Subject', 'Browse Standard Ebooks by subject.', '/feeds/opds/subjects', WEB_ROOT . '/feeds/opds/subjects/index.xml', $subjectNavigationEntries, $opdsRoot);
$subjectsFeed->Subtitle = 'Browse Standard Ebooks by subject.';
SaveFeed($subjectsFeed, $force, $now);

// Now generate each individual subject feed
foreach($subjectNavigationEntries as $subjectNavigationEntry){
krsort($ebooksBySubject[$subjectNavigationEntry->Title]);
$subjectFeed = new OpdsAcquisitionFeed($subjectNavigationEntry->Title . ' Ebooks', $subjectNavigationEntry->Description, '/opds/subjects/' . Formatter::MakeUrlSafe($subjectNavigationEntry->Title), WEB_ROOT . '/opds/subjects/' . Formatter::MakeUrlSafe($subjectNavigationEntry->Title) . '.xml', $ebooksBySubject[$subjectNavigationEntry->Title], $subjectsFeed);
$subjectFeed = new OpdsAcquisitionFeed($subjectNavigationEntry->Title . ' Ebooks', $subjectNavigationEntry->Description, '/feeds/opds/subjects/' . Formatter::MakeUrlSafe($subjectNavigationEntry->Title), WEB_ROOT . '/feeds/opds/subjects/' . Formatter::MakeUrlSafe($subjectNavigationEntry->Title) . '.xml', $ebooksBySubject[$subjectNavigationEntry->Title], $subjectsFeed);
SaveFeed($subjectFeed, $force, $now);
}

// Create the 'all' feed
krsort($allEbooks);
$allFeed = new OpdsAcquisitionFeed('All Standard Ebooks', 'All Standard Ebooks, most-recently-updated first. This is a Complete Acquisition Feed as defined in OPDS 1.2 §2.5.', '/opds/all', WEB_ROOT . '/opds/all.xml', $allEbooks, $opdsRoot, true);
$allFeed = new OpdsAcquisitionFeed('All Standard Ebooks', 'All Standard Ebooks, most-recently-updated first. This is a Complete Acquisition Feed as defined in OPDS 1.2 §2.5.', '/feeds/opds/all', WEB_ROOT . '/feeds/opds/all.xml', $allEbooks, $opdsRoot, true);
SaveFeed($allFeed, $force, $now);

// Create the 'newest' feed
$newestFeed = new OpdsAcquisitionFeed('Newest ' . number_format($ebooksPerNewestEbooksFeed) . ' Standard Ebooks', 'The ' . number_format($ebooksPerNewestEbooksFeed) . ' latest Standard Ebooks, most-recently-released first.', '/opds/new-releases', WEB_ROOT . '/opds/new-releases.xml', $newestEbooks, $opdsRoot);
$newestFeed = new OpdsAcquisitionFeed('Newest ' . number_format($ebooksPerNewestEbooksFeed) . ' Standard Ebooks', 'The ' . number_format($ebooksPerNewestEbooksFeed) . ' latest Standard Ebooks, most-recently-released first.', '/feeds/opds/new-releases', WEB_ROOT . '/feeds/opds/new-releases.xml', $newestEbooks, $opdsRoot);
SaveFeed($newestFeed, $force, $now);

// Now create RSS feeds

// Create the 'newest' feed
$newestRssFeed = new RssFeed('Standard Ebooks - Newest Ebooks', 'The ' . number_format($ebooksPerNewestEbooksFeed) . ' latest Standard Ebooks, most-recently-released first.', '/rss/new-releases', WEB_ROOT . '/rss/new-releases.xml', $newestEbooks);
$newestRssFeed = new RssFeed('Standard Ebooks - Newest Ebooks', 'The ' . number_format($ebooksPerNewestEbooksFeed) . ' latest Standard Ebooks, most-recently-released first.', '/feeds/rss/new-releases', WEB_ROOT . '/feeds/rss/new-releases.xml', $newestEbooks);
SaveFeed($newestRssFeed, $force);

// Create the 'all' feed
$allRssFeed = new RssFeed('Standard Ebooks - All Ebooks', 'All Standard Ebooks, most-recently-released first.', '/rss/all', WEB_ROOT . '/rss/all.xml', $allEbooks);
$allRssFeed = new RssFeed('Standard Ebooks - All Ebooks', 'All Standard Ebooks, most-recently-released first.', '/feeds/rss/all', WEB_ROOT . '/feeds/rss/all.xml', $allEbooks);
SaveFeed($allRssFeed, $force);

// Generate each individual subject feed
foreach($ebooksBySubject as $subject => $ebooks){
krsort($ebooks);
$subjectRssFeed = new RssFeed('Standard Ebooks - ' . (string)$subject . ' Ebooks', 'Standard Ebooks tagged with “' . strtolower($subject) . ',” most-recently-released first.', '/rss/subjects/' . Formatter::MakeUrlSafe((string)$subject), WEB_ROOT . '/rss/subjects/' . Formatter::MakeUrlSafe((string)$subject) . '.xml', $ebooks);
$subjectRssFeed = new RssFeed('Standard Ebooks - ' . (string)$subject . ' Ebooks', 'Standard Ebooks tagged with “' . strtolower($subject) . ',” most-recently-released first.', '/feeds/rss/subjects/' . Formatter::MakeUrlSafe((string)$subject), WEB_ROOT . '/feeds/rss/subjects/' . Formatter::MakeUrlSafe((string)$subject) . '.xml', $ebooks);
SaveFeed($subjectRssFeed, $force);
}

// Now create the Atom feeds
// Create the 'newest' feed
$newestAtomFeed = new AtomFeed('Standard Ebooks - Newest Ebooks', 'The ' . number_format($ebooksPerNewestEbooksFeed) . ' latest Standard Ebooks, most-recently-released first.', '/atom/new-releases', WEB_ROOT . '/atom/new-releases.xml', $newestEbooks);
$newestAtomFeed = new AtomFeed('Standard Ebooks - Newest Ebooks', 'The ' . number_format($ebooksPerNewestEbooksFeed) . ' latest Standard Ebooks, most-recently-released first.', '/feeds/atom/new-releases', WEB_ROOT . '/feeds/atom/new-releases.xml', $newestEbooks);
SaveFeed($newestAtomFeed, $force, $now);

// Create the 'all' feed
$allAtomFeed = new AtomFeed('Standard Ebooks - All Ebooks', 'All Standard Ebooks, most-recently-released first.', '/atom/all', WEB_ROOT . '/atom/all.xml', $allEbooks);
$allAtomFeed = new AtomFeed('Standard Ebooks - All Ebooks', 'All Standard Ebooks, most-recently-released first.', '/feeds/atom/all', WEB_ROOT . '/feeds/atom/all.xml', $allEbooks);
SaveFeed($allAtomFeed, $force, $now);

// Generate each individual subject feed
foreach($ebooksBySubject as $subject => $ebooks){
krsort($ebooks);
$subjectAtomFeed = new AtomFeed('Standard Ebooks - ' . (string)$subject . ' Ebooks', 'Standard Ebooks tagged with “' . strtolower($subject) . ',” most-recently-released first.', '/atom/subjects/' . Formatter::MakeUrlSafe((string)$subject), WEB_ROOT . '/atom/subjects/' . Formatter::MakeUrlSafe((string)$subject) . '.xml', $ebooks);
$subjectAtomFeed = new AtomFeed('Standard Ebooks - ' . (string)$subject . ' Ebooks', 'Standard Ebooks tagged with “' . strtolower($subject) . ',” most-recently-released first.', '/feeds/atom/subjects/' . Formatter::MakeUrlSafe((string)$subject), WEB_ROOT . '/feeds/atom/subjects/' . Formatter::MakeUrlSafe((string)$subject) . '.xml', $ebooks);
SaveFeed($subjectAtomFeed, $force, $now);
}
?>
4 changes: 3 additions & 1 deletion templates/Header.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@
<link href="/favicon-32x32.png" rel="icon" sizes="32x32" type="image/png"/>
<link href="/favicon-16x16.png" rel="icon" sizes="16x16" type="image/png"/>
<link href="/manifest.json" rel="manifest"/>
<link rel="alternate" type="application/rss+xml" title="Standard Ebooks - New Releases" href="https://standardebooks.org/rss/new-releases"/>
<link rel="alternate" type="application/atom+xml" title="Standard Ebooks - New Releases" href="https://standardebooks.org/feeds/atom/new-releases"/>
<link rel="alternate" type="application/atom+xml;profile=opds-catalog;kind=acquisition" title="Standard Ebooks - New Releases" href="https://standardebooks.org/feeds/opds/new-releases"/>
<link rel="alternate" type="application/rss+xml" title="Standard Ebooks - New Releases" href="https://standardebooks.org/feeds/rss/new-releases"/>
<meta content="#394451" name="theme-color"/>
<meta content="<? if($title != ''){ ?><?= Formatter::ToPlainText($title) ?><? }else{ ?>Standard Ebooks<? } ?>" property="og:title"/>
<meta content="<?= $ogType ?? 'website' ?>" property="og:type"/>
Expand Down
6 changes: 3 additions & 3 deletions templates/OpdsAcquisitionFeed.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

/* Notes:
- *All* OPDS feeds must contain a rel="http://opds-spec.org/crawlable" link pointing to the /opds/all feed
- *All* OPDS feeds must contain a rel="http://opds-spec.org/crawlable" link pointing to the /feeds/opds/all feed
- The <fh:complete/> element is required to note this as a "Complete Acquisition Feeds"; see https://specs.opds.io/opds-1.2#25-complete-acquisition-feeds
Expand All @@ -19,9 +19,9 @@
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:schema="http://schema.org/"<? if($isCrawlable){ ?> xmlns:fh="http://purl.org/syndication/history/1.0"<? } ?>>
<id><?= SITE_URL . Formatter::ToPlainXmlText($id) ?></id>
<link href="<?= SITE_URL . Formatter::ToPlainXmlText($url) ?>" rel="self" type="application/atom+xml;profile=opds-catalog;kind=acquisition"/>
<link href="<?= SITE_URL ?>/opds" rel="start" type="application/atom+xml;profile=opds-catalog;kind=navigation"/>
<link href="<?= SITE_URL ?>/feeds/opds" rel="start" type="application/atom+xml;profile=opds-catalog;kind=navigation"/>
<link href="<?= SITE_URL ?><?= Formatter::ToPlainXmlText($parentUrl) ?>" rel="up" type="application/atom+xml;profile=opds-catalog;kind=navigation"/>
<link href="<?= SITE_URL ?>/opds/all" rel="http://opds-spec.org/crawlable" type="application/atom+xml;profile=opds-catalog;kind=acquisition"/>
<link href="<?= SITE_URL ?>/feeds/opds/all" rel="http://opds-spec.org/crawlable" type="application/atom+xml;profile=opds-catalog;kind=acquisition"/>
<link href="<?= SITE_URL ?>/ebooks/opensearch" rel="search" type="application/opensearchdescription+xml"/>
<title><?= Formatter::ToPlainXmlText($title) ?></title>
<? if($subtitle !== null){ ?><subtitle><?= Formatter::ToPlainXmlText($subtitle) ?></subtitle><? } ?>
Expand Down
4 changes: 2 additions & 2 deletions templates/OpdsNavigationFeed.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
<id><?= SITE_URL . Formatter::ToPlainXmlText($id) ?></id>
<link href="<?= SITE_URL . Formatter::ToPlainXmlText($url) ?>" rel="self" type="application/atom+xml;profile=opds-catalog;kind=navigation"/>
<link href="<?= SITE_URL ?>/opds" rel="start" type="application/atom+xml;profile=opds-catalog;kind=navigation"/>
<link href="<?= SITE_URL ?>/opds/all" rel="http://opds-spec.org/crawlable" type="application/atom+xml;profile=opds-catalog;kind=acquisition"/>
<link href="<?= SITE_URL ?>/feeds/opds" rel="start" type="application/atom+xml;profile=opds-catalog;kind=navigation"/>
<link href="<?= SITE_URL ?>/feeds/opds/all" rel="http://opds-spec.org/crawlable" type="application/atom+xml;profile=opds-catalog;kind=acquisition"/>
<link href="<?= SITE_URL ?>/ebooks/opensearch" rel="search" type="application/opensearchdescription+xml"/>
<? if($parentUrl !== null){ ?><link href="<?= SITE_URL ?><?= Formatter::ToPlainXmlText($parentUrl) ?>" rel="up" type="application/atom+xml;profile=opds-catalog;kind=navigation"/><? } ?>
<title><?= Formatter::ToPlainXmlText($title) ?></title>
Expand Down
4 changes: 2 additions & 2 deletions www/ebooks/opensearch.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<SyndicationRight>open</SyndicationRight>
<OutputEncoding>UTF-8</OutputEncoding>
<InputEncoding>UTF-8</InputEncoding>
<Url type="text/html" template="https://standardebooks.org/ebooks?query={searchTerms}&amp;per-page={count}&amp;page={startPage}"/>
<Url type="application/atom+xml;profile=opds-catalog;kind=acquisition" template="https://standardebooks.org/opds/all?query={searchTerms}"/>
<Url type="application/xhtml+xml" template="https://standardebooks.org/ebooks?query={searchTerms}&amp;per-page={count}&amp;page={startPage}"/>
<Url type="application/atom+xml;profile=opds-catalog;kind=acquisition" template="https://standardebooks.org/feeds/opds/all?query={searchTerms}"/>
<Query role="example" searchTerms="fiction" startPage="1" count="12"/>
</OpenSearchDescription>
Loading

0 comments on commit c109c56

Please sign in to comment.