Add feed/download toolbar to author and collection indexes

This commit is contained in:
Alex Cabal 2022-07-12 10:18:20 -05:00
parent 4268c6f91c
commit dc0e873577
14 changed files with 151 additions and 43 deletions

View file

@ -246,9 +246,11 @@ Define webroot /standardebooks.org/web
RewriteRule ^/ebooks/([^\./]+?)$ /ebooks/author.php?url-path=$1 [QSA]
RewriteRule ^/ebooks/([^\./]+?)/downloads$ /bulk-downloads/get.php?author=$1 [QSA]
RewriteRule ^/ebooks/([^\./]+?)/feeds$ /feeds/get.php?author=$1 [QSA]
RewriteRule ^/subjects/([^\./]+?)$ /ebooks/index.php?tags[]=$1 [QSA]
RewriteRule ^/collections/([^\./]+?)$ /ebooks/index.php?collection=$1 [QSA]
RewriteRule ^/collections/([^/]+?)/downloads$ /bulk-downloads/get.php?collection=$1
RewriteRule ^/collections/([^/]+?)/feeds$ /feeds/get.php?collection=$1
# Prevent this rule from firing if we're getting a distribution file
RewriteCond %{REQUEST_FILENAME} !^/ebooks/.+?/downloads/.+$

View file

@ -228,9 +228,11 @@ Define webroot /standardebooks.org/web
RewriteRule ^/ebooks/([^\./]+?)$ /ebooks/author.php?url-path=$1 [QSA]
RewriteRule ^/ebooks/([^\./]+?)/downloads$ /bulk-downloads/get.php?author=$1 [QSA]
RewriteRule ^/ebooks/([^\./]+?)/feeds$ /feeds/get.php?author=$1 [QSA]
RewriteRule ^/subjects/([^\./]+?)$ /ebooks/index.php?tags[]=$1 [QSA]
RewriteRule ^/collections/([^\./]+?)$ /ebooks/index.php?collection=$1 [QSA]
RewriteRule ^/collections/([^/]+?)/downloads$ /bulk-downloads/get.php?collection=$1
RewriteRule ^/collections/([^/]+?)/feeds$ /feeds/get.php?collection=$1
# Prevent this rule from firing if we're getting a distribution file
RewriteCond %{REQUEST_FILENAME} !^/ebooks/.+?/downloads/.+$

View file

@ -7,6 +7,7 @@ class OpdsNavigationEntry{
public $Updated;
public $Description;
public $Title;
public $SortTitle;
public function __construct(string $title, string $description, string $url, ?DateTime $updated, string $rel, string $type){
$this->Id = SITE_URL . $url;

View file

@ -38,10 +38,12 @@ function CreateOpdsCollectionFeed(string $name, string $url, string $description
// Create the collections navigation document
$collectionNavigationEntries = [];
foreach($collections as $collection){
$collectionNavigationEntries[] = new OpdsNavigationEntry($collection['name'], str_replace('%s', $collection['name'], $description), $url . '/' . $collection['id'], $now, 'subsection', 'navigation');
$entry = new OpdsNavigationEntry($collection['name'], str_replace('%s', $collection['name'], $description), $url . '/' . $collection['id'], $now, 'subsection', 'navigation');
$entry->SortTitle = $collection['sortedname'];
$collectionNavigationEntries[] = $entry;
}
$collectionsFeed = new OpdsNavigationFeed('Standard Ebooks by ' . ucfirst($name), 'Browse Standard Ebooks by ' . $name . '.', $url, $webRoot . $url . '/index.xml', $collectionNavigationEntries, $opdsRoot);
$collectionsFeed->Subtitle = 'Browse Standard Ebooks by collection.';
$collectionsFeed->Subtitle = 'Browse Standard Ebooks by ' . $name . '.';
SaveFeed($collectionsFeed, $force, null, null, $now);
// Now generate each individual collection feed
@ -49,7 +51,7 @@ function CreateOpdsCollectionFeed(string $name, string $url, string $description
$id = basename($collectionNavigationEntry->Id);
usort($ebooks[$id], 'SortByUpdatedDesc');
$collectionFeed = new OpdsAcquisitionFeed($collectionNavigationEntry->Title . ' Ebooks', $collectionNavigationEntry->Description, $url . '/' . $id, $webRoot . $url . '/' . $id . '.xml', $ebooks[$id], $collectionsFeed);
SaveFeed($collectionFeed, $force, null, null, $now);
SaveFeed($collectionFeed, $force, $collectionNavigationEntry->Title, $collectionNavigationEntry->SortTitle, $now);
}
}

View file

@ -1,21 +1,12 @@
<section id="accessing-the-feeds">
<h2>Accessing the feeds</h2>
<p>Our New Releases feeds are accessible by the public. Access to our other, more detailed feeds is available to our <a href="/about#patrons-circle">Patrons Circle supporters</a> and our <a href="/about#corporate-sponsors">corporate sponsors</a>.</p>
<p><i>If youre a Patrons Circle member, when prompted enter your email address and leave the password field blank to access a feed.</i></p>
<? if($GLOBALS['User'] === null){ ?>
<section id="individuals">
<h3>Access for individuals</h3>
<ul>
<li><p>Join the <a href="/donate#patrons-circle">Patrons Circle</a> by making a donation to get access to all of our ebook feeds for the duration of your gift.</p></li>
<li><p><a href="/contribute">Produce an ebook</a> for Standard Ebooks to get lifetime access to our ebook feeds. If youve already done that, <a href="/about#editor-in-chief">contact us</a> to enable your access.</p></li>
</ul>
</section>
<section id="organizations-and-projects">
<h3>Access for organizations and projects</h3>
<p>Our New Releases feeds are open to everyone. Our other feeds are a benefit of Patrons Circle membership.</p>
<ul>
<li><p><a href="/donate#patrons-circle">Join the Patrons Circle</a> by making a small donation in support of our mission. Patrons have full access to our ebook feeds for the duration of their gift.</p></li>
<li><p><a href="/contribute">Produce an ebook</a> for Standard Ebooks to get lifetime access to our ebook feeds. (If youve already done that, <a href="/about#editor-in-chief">contact us</a> to enable your access.)</p></li>
<li><p><a href="/donate#corporate-sponsors">Corporate sponsors</a> get access to all of our ebook feeds for the duration of their sponsorship. <a href="/about#editor-in-chief">Contact us</a> to chat about having your organization sponsor our mission.</p></li>
<li><p>Software projects that are open-source and not-for-profit may be granted free access to our feeds. <a href="/about#editor-in-chief">Contact us</a> to inquire.</p></li>
</ul>
</section>
<? } ?>
<p><i>If youre a Patrons Circle member, when prompted enter your email address and leave the password field blank to access a feed.</i></p>
</section>

View file

@ -2352,13 +2352,43 @@ h1.is-collection{
margin-bottom: 1rem;
}
.download-collection{
.ebooks-toolbar{
display: flex;
justify-content: center;
justify-content: flex-end;
margin-bottom: 4rem;
border-bottom: 1px dashed var(--sub-text);
padding-bottom: 1rem;
font-style: italic;
gap: 1rem;
}
.ebooks-toolbar a{
padding: .5rem 1rem;
padding-left: .75rem;
text-decoration: none;
}
.ebooks-toolbar a.button{
/*font-family: "Crimson Pro", Georgia, serif;*/
font-size: .75rem;
display: inline-flex;
gap: .75rem;
align-items: center;
font-weight: bold;
}
.ebooks-toolbar a.button::before{
font-family: "Fork Awesome";
display: inline-block;
font-size: 1rem;
}
.ebooks-toolbar a.button[href*="/downloads"]::before{
content: "\f019";
}
.ebooks-toolbar a.button[href*="/feeds"]::before{
content: "\f143";
}
abbr.acronym{
@ -3099,6 +3129,15 @@ ul.feed p{
white-space: normal;
margin: 0 10px;
}
.ebooks-toolbar{
}
.ebooks-toolbar a.button{
font-size: 0;
gap: 0;
padding: .5rem .75rem;
}
}
@media(max-width: 680px){

View file

@ -23,10 +23,11 @@ catch(Exceptions\InvalidAuthorException $ex){
}
?><?= Template::Header(['title' => 'Ebooks by ' . strip_tags($ebooks[0]->AuthorsHtml), 'highlight' => 'ebooks', 'description' => 'All of the Standard Ebooks ebooks by ' . strip_tags($ebooks[0]->AuthorsHtml)]) ?>
<main class="ebooks">
<h1<? if(sizeof($ebooks) > 1){ ?> class="is-collection"<? } ?>>Ebooks by <?= $ebooks[0]->AuthorsHtml ?></h1>
<? if(sizeof($ebooks) > 1){ ?>
<p class="download-collection"><a href="<?= Formatter::ToPlainText($ebooks[0]->AuthorsUrl) ?>/downloads">Download all ebooks in this collection</a></p>
<? } ?>
<h1 class="is-collection">Ebooks by <?= $ebooks[0]->AuthorsHtml ?></h1>
<p class="ebooks-toolbar">
<a class="button" href="<?= Formatter::ToPlainText($ebooks[0]->AuthorsUrl) ?>/downloads">Download collection</a>
<a class="button" href="<?= Formatter::ToPlainText($ebooks[0]->AuthorsUrl) ?>/feeds">Author feeds</a>
</p>
<?= Template::EbookGrid(['ebooks' => $ebooks, 'view' => VIEW_GRID]) ?>
<p class="feeds-alert">We also have <a href="/bulk-downloads">bulk ebook downloads</a> available, as well as <a href="/feeds">ebook catalog feeds</a> for use directly in your ereader app or RSS reader.</p>
<?= Template::ContributeAlert() ?>

View file

@ -118,7 +118,7 @@ catch(Exceptions\InvalidCollectionException $ex){
}
?><?= Template::Header(['title' => $pageTitle, 'highlight' => 'ebooks', 'description' => $pageDescription]) ?>
<main class="ebooks">
<h1<? if($collection !== null && sizeof($ebooks) > 1){ ?> class="is-collection"<? } ?>><?= $pageHeader ?></h1>
<h1<? if($collection !== null){ ?> class="is-collection"<? } ?>><?= $pageHeader ?></h1>
<?= Template::DonationCounter() ?>
<?= Template::DonationProgress() ?>
<? if(!DONATION_DRIVE_ON && !DONATION_DRIVE_COUNTER_ON && DONATION_HOLIDAY_ALERT_ON){ ?>
@ -127,8 +127,11 @@ catch(Exceptions\InvalidCollectionException $ex){
<? if($collection === null){ ?>
<?= Template::SearchForm(['query' => $query, 'tags' => $tags, 'sort' => $sort, 'view' => $view, 'perPage' => $perPage]) ?>
<? } ?>
<? if($collection !== null && sizeof($ebooks) > 1){ ?>
<p class="download-collection"><a href="/collections/<?= Formatter::ToPlainText($collection) ?>/downloads">Download all ebooks in this collection</a></p>
<? if($collection !== null){ ?>
<p class="ebooks-toolbar">
<a class="button" href="/collections/<?= Formatter::ToPlainText($collection) ?>/downloads">Download collection</a>
<a class="button" href="/collections/<?= Formatter::ToPlainText($collection) ?>/feeds">Collection feeds</a>
</p>
<? } ?>
<? if(sizeof($ebooks) == 0){ ?>
<p class="no-results">No ebooks matched your filters. You can try different filters, or <a href="/ebooks">browse all of our ebooks</a>.</p>

View file

@ -42,18 +42,9 @@ if($type == 'atom'){
</picture>
<ul class="message error">
<li>
<p>You must be a member of the <a href="/donate#patrons-circle">Patrons Circle</a> to access the ebook feeds.</p>
<p>Make a donation to <a href="/donate#patrons-circle">join the Patrons Circle</a> and get access our ebook feeds.</p>
</li>
</ul>
<? if($type == 'opds'){ ?>
<p><a href="https://en.wikipedia.org/wiki/Open_Publication_Distribution_System">OPDS feeds</a>, or “catalogs, can be added to ereading apps on phones and tablets to search, browse, and download from our entire catalog, directly in your ereader. Most modern ereading apps support OPDS catalogs.</p>
<p>Theyre also perfect for scripting, or for libraries or other organizations who wish to download and process our catalog of ebooks.</p>
<? }elseif($type == 'rss'){ ?>
<p>RSS feeds are the predecessors of <a href="/feeds/atom">Atom feeds</a>. They contain less information than Atom feeds, but might be better supported by some news readers.</p>
<? }elseif($type == 'atom'){ ?>
<p>Atom feeds can be read by one of the many <a href="https://en.wikipedia.org/wiki/Comparison_of_feed_aggregators">RSS clients</a> available for download, like <a href="https://www.thunderbird.net/en-US/">Thunderbird</a>. They contain more information than regular <a href="/feeds/rss">RSS feeds</a>. Most RSS clients can read both Atom and RSS feeds.</p>
<p>Note that some RSS readers may show these feeds ordered by when an ebook was last updated, even though the feeds are ordered by when an ebook was first released. You should be able to change the sort order in your RSS reader.</p>
<? } ?>
<?= Template::FeedHowTo() ?>
</section>
</main>

View file

@ -9,7 +9,7 @@ require_once('Core.php');
<p>Note that some RSS readers may show these feeds ordered by when an ebook was last updated, even though the feeds are ordered by when an ebook was first released. You should be able to change the sort order in your RSS reader.</p>
<?= Template::FeedHowTo() ?>
<section id="general-feeds">
<h2>General feeds</h2>
<h2>General Atom feeds</h2>
<ul class="feed">
<li>
<p><a href="/feeds/atom/new-releases">New releases</a> (Public)</p>
@ -24,7 +24,7 @@ require_once('Core.php');
</ul>
</section>
<section id="feeds-by-topic">
<h2>Feeds by topic</h2>
<h2>Atom feeds by topic</h2>
<ul class="feed">
<li>
<p><a href="/feeds/atom/authors">Feeds by author</a></p>

75
www/feeds/get.php Normal file
View file

@ -0,0 +1,75 @@
<?
require_once('Core.php');
$author = HttpInput::Str(GET, 'author', false);
$collection = HttpInput::Str(GET, 'collection', false);
$name = null;
$target = null;
$feedTypes = ['opds', 'atom', 'rss'];
$title = '';
$description = '';
$label = null;
if($author !== null){
$name = 'authors';
$target = $author;
}
if($collection !== null){
$name = 'collections';
$target = $collection;
}
try{
if($target === null || $name === null){
throw new Exceptions\InvalidCollectionException();
}
$file = WEB_ROOT . '/feeds/opds/' . $name . '/' . $target . '.xml';
if(!is_file($file)){
throw new Exceptions\InvalidCollectionException();
}
$label = exec('attr -g se-label ' . escapeshellarg($file)) ?: basename($file, '.xml');
if($name == 'authors'){
$title = 'Ebook feeds for ' . $label;
$description = 'A list of available ebook feeds for ebooks by ' . $label . '.';
}
if($name == 'collections'){
$title = 'Ebook feeds for the ' . $label . ' collection';
$description = 'A list of available ebook feeds for ebooks in the ' . $label . ' collection.';
}
}
catch(Exceptions\InvalidCollectionException $ex){
Template::Emit404();
}
?><?= Template::Header(['title' => $title, 'description' => $description]) ?>
<main>
<article>
<h1>Ebook Feeds for <?= Formatter::ToPlainText($label) ?></h1>
<?= Template::FeedHowTo() ?>
<? foreach($feedTypes as $type){ ?>
<section id="ebooks-by-<?= $type ?>">
<h2><? if($type == 'rss'){ ?>RSS 2.0<? } ?><? if($type == 'atom'){ ?>Atom 1.0<? } ?><? if($type == 'opds'){ ?>OPDS 1.2<? } ?> Feed</h2>
<? if($type == 'opds'){ ?>
<p>Import this feed into your ereader app to get access to these ebooks directly in your ereader.</p>
<? } ?>
<? if($type == 'atom'){ ?>
<p>Get updates in your <a href="https://en.wikipedia.org/wiki/Comparison_of_feed_aggregators">RSS client</a> whenever a new ebook is released, or parse this feed for easy scripting.</p>
<? } ?>
<? if($type == 'rss'){ ?>
<p>The predecessor of Atom, compatible with most RSS clients.</p>
<? } ?>
<ul class="feed">
<li>
<p><a href="<? if($GLOBALS['User'] !== null){ ?>https://<?= rawurlencode($GLOBALS['User']->Email) ?>@<?= SITE_DOMAIN ?><? } ?>/feeds/<?= $type ?>/<?= $name ?>/<?= $target?>"><?= Formatter::ToPlainText($label) ?></a></p>
<p class="url"><? if($GLOBALS['User'] !== null){ ?>https://<?= rawurlencode($GLOBALS['User']->Email) ?>@<?= SITE_DOMAIN ?><? }else{ ?><?= SITE_URL ?><? } ?>/feeds/<?= $type ?>/<?= $name ?>/<?= $target?></p>
</li>
</ul>
</section>
<? } ?>
</article>
</main>
<?= Template::Footer() ?>

View file

@ -14,8 +14,9 @@ require_once('Core.php');
<?= Template::FeedHowTo() ?>
<section id="opds-feeds">
<h2>OPDS 1.2 feeds</h2>
<p><a href="https://en.wikipedia.org/wiki/Open_Publication_Distribution_System">OPDS feeds</a>, or “catalogs, can be added to ereading apps on phones and tablets to search, browse, and download from our entire catalog, directly in your ereader. Most modern ereading apps support OPDS catalogs.</p>
<p><a href="https://en.wikipedia.org/wiki/Open_Publication_Distribution_System">OPDS feeds</a>, or “catalogs, can be added to ereading apps on phones and tablets to search, browse, and download from our ebook catalog, directly in your ereader. Most modern ereading apps support OPDS catalogs.</p>
<p>Theyre also perfect for scripting, or for libraries or other organizations who wish to download, process, and keep up to date with our catalog of ebooks.</p>
<p>To connect your ereading app to our catalog, enter the URL below when prompted by your app:</p>
<ul class="feed">
<li>
<p><a href="<? if($GLOBALS['User'] !== null){ ?>https://<?= rawurlencode($GLOBALS['User']->Email) ?>@<?= SITE_DOMAIN ?><? } ?>/feeds/opds">The Standard Ebooks OPDS feed</a></p>

View file

@ -8,7 +8,7 @@ require_once('Core.php');
<p>RSS feeds are the predecessors of <a href="/feeds/atom">Atom feeds</a>. They contain less information than Atom feeds, but might be better supported by some news readers.</p>
<?= Template::FeedHowTo() ?>
<section id="general-feeds">
<h2>General feeds</h2>
<h2>General RSS feeds</h2>
<ul class="feed">
<li>
<p><a href="/feeds/rss/new-releases">New releases</a> (Public)</p>
@ -23,7 +23,7 @@ require_once('Core.php');
</ul>
</section>
<section id="ebooks-by-collection">
<h2>Feeds by topic</h2>
<h2>RSS feeds by topic</h2>
<ul class="feed">
<li>
<p><a href="/feeds/rss/authors">Feeds by author</a></p>

Binary file not shown.