diff --git a/.gitignore b/.gitignore index a3ecc298..2aca67de 100644 --- a/.gitignore +++ b/.gitignore @@ -2,11 +2,11 @@ ebooks/* www/ebooks/* www/images/covers/* www/feeds/opds/*.xml -www/feeds/opds/subjects/*.xml +www/feeds/opds/*/*.xml www/feeds/rss/*.xml -www/feeds/rss/subjects/*.xml +www/feeds/rss/*/*.xml www/feeds/atom/*.xml -www/feeds/atom/subjects/*.xml +www/feeds/atom/*/*.xml vendor/ composer.lock .vagrant/ diff --git a/config/apache/standardebooks.org.conf b/config/apache/standardebooks.org.conf index 0571cfb4..eff42f49 100644 --- a/config/apache/standardebooks.org.conf +++ b/config/apache/standardebooks.org.conf @@ -279,6 +279,8 @@ Define webroot /standardebooks.org/web RewriteCond %{QUERY_STRING} \bquery= RewriteRule ^/feeds/(opds|atom|rss)/all.xml$ /feeds/$1/search.php [QSA] + RewriteRule ^/feeds/(atom|rss)/([^/\.]+)$ /feeds/collection.php?type=$1&name=$2 + # Rewrite rules for bulk downloads RewriteRule ^/bulk-downloads/(.+\.zip)$ /bulk-downloads/download.php?path=$1 RewriteRule ^/bulk-downloads/([^/\.]+)$ /bulk-downloads/collection.php?name=$1 diff --git a/config/apache/standardebooks.test.conf b/config/apache/standardebooks.test.conf index d1ccf9a6..593ce8eb 100644 --- a/config/apache/standardebooks.test.conf +++ b/config/apache/standardebooks.test.conf @@ -261,6 +261,8 @@ Define webroot /standardebooks.org/web RewriteCond %{QUERY_STRING} \bquery= RewriteRule ^/feeds/(opds|atom|rss)/all.xml$ /feeds/$1/search.php [QSA] + RewriteRule ^/feeds/(atom|rss)/([^/\.]+)$ /feeds/collection.php?type=$1&name=$2 + # Rewrite rules for bulk downloads RewriteRule ^/bulk-downloads/(.+\.zip)$ /bulk-downloads/download.php?path=$1 RewriteRule ^/bulk-downloads/([^/\.]+)$ /bulk-downloads/collection.php?name=$1 diff --git a/lib/AtomFeed.php b/lib/AtomFeed.php index f5d75bef..042adbd1 100644 --- a/lib/AtomFeed.php +++ b/lib/AtomFeed.php @@ -23,7 +23,7 @@ class AtomFeed extends Feed{ parent::__construct($title, $url, $path, $entries); $this->Subtitle = $subtitle; $this->Id = $url; - $this->Stylesheet = '/feeds/atom/style'; + $this->Stylesheet = SITE_URL . '/feeds/atom/style'; } @@ -41,13 +41,16 @@ class AtomFeed extends Feed{ return $this->XmlString; } - public function SaveIfChanged(): void{ + public function SaveIfChanged(): bool{ // Did we actually update the feed? If so, write to file and update the index if($this->HasChanged($this->Path)){ // Files don't match, save the file $this->Updated = new DateTime(); $this->Save(); + return true; } + + return false; } protected function HasChanged(string $path): bool{ diff --git a/lib/Library.php b/lib/Library.php index 254f8ebc..eb11e8f8 100644 --- a/lib/Library.php +++ b/lib/Library.php @@ -322,7 +322,10 @@ class Library{ * @return array>> */ public static function RebuildBulkDownloadsCache(): array{ - $collator = collator_create( 'en_US' ); // Used for sorting letters with diacritics like in author names + $collator = Collator::create('en_US'); // Used for sorting letters with diacritics like in author names + if($collator === null){ + throw new Exceptions\SeException('Couldn\'t create collator object when rebuilding bulk download cache.'); + } $months = []; $subjects = []; $collections = []; diff --git a/lib/OpdsFeed.php b/lib/OpdsFeed.php index e25b8230..581ffb07 100644 --- a/lib/OpdsFeed.php +++ b/lib/OpdsFeed.php @@ -16,7 +16,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 = '/feeds/opds/style'; + $this->Stylesheet = SITE_URL . '/feeds/opds/style'; } @@ -45,7 +45,7 @@ class OpdsFeed extends AtomFeed{ } } - public function SaveIfChanged(): void{ + public function SaveIfChanged(): bool{ // Did we actually update the feed? If so, write to file and update the index if($this->HasChanged($this->Path)){ // Files don't match, save the file and update the parent navigation feed with the last updated timestamp @@ -58,6 +58,9 @@ class OpdsFeed extends AtomFeed{ // Save our own file $this->Save(); + return true; } + + return false; } } diff --git a/lib/RssFeed.php b/lib/RssFeed.php index b1069dd7..ad5a7e75 100644 --- a/lib/RssFeed.php +++ b/lib/RssFeed.php @@ -17,7 +17,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 = '/feeds/rss/style'; + $this->Stylesheet = SITE_URL . '/feeds/rss/style'; } @@ -35,12 +35,15 @@ class RssFeed extends Feed{ return $this->XmlString; } - public function SaveIfChanged(): void{ + public function SaveIfChanged(): bool{ // Did we actually update the feed? If so, write to file and update the index if($this->HasChanged($this->Path)){ // Files don't match, save the file $this->Save(); + return true; } + + return false; } protected function HasChanged(string $path): bool{ diff --git a/scripts/generate-feeds b/scripts/generate-feeds index cccb0659..7a825c84 100755 --- a/scripts/generate-feeds +++ b/scripts/generate-feeds @@ -2,24 +2,58 @@ Updated <=> $a->Updated; +} + +function SaveFeed(Feed $feed, bool $force, ?string $label = null, ?string $labelSort = null, DateTime $now = null): void{ + $updateAttrs = false; + if($force){ if($now !== null){ $feed->Updated = $now; } $feed->Save(); + $updateAttrs = true; } else{ - $feed->SaveIfChanged(); + $updateAttrs = $feed->SaveIfChanged(); + } + + if($updateAttrs && $label !== null && $labelSort !== null){ + exec('attr -q -s se-label -V ' . escapeshellarg($label) . ' ' . escapeshellarg($feed->Path)); + exec('attr -q -s se-label-sort -V ' . escapeshellarg($labelSort) . ' ' . escapeshellarg($feed->Path)); } } +function CreateOpdsCollectionFeed(string $name, string $url, string $description, array $collections, array $ebooks, DateTime $now, string $webRoot, OpdsNavigationFeed $opdsRoot, bool $force): void{ + $collator = collator_create('en_US'); // Used for sorting letters with diacritics like in author names + usort($collections, function($a, $b) use($collator){ return $collator->compare($a['sortedname'], $b['sortedname']); }); + + // 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'); + } + $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.'; + SaveFeed($collectionsFeed, $force, null, null, $now); + + // Now generate each individual collection feed + foreach($collectionNavigationEntries as $collectionNavigationEntry){ + $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); + } +} + + $longopts = ['webroot:', 'force']; $options = getopt('', $longopts); $webRoot = $options['webroot'] ?? WEB_ROOT; @@ -29,37 +63,47 @@ $allEbooks = []; $newestEbooks = []; $subjects = []; $ebooksBySubject = []; +$collections = []; +$ebooksByCollection = []; +$authors = []; +$ebooksByAuthor = []; $ebooksPerNewestEbooksFeed = 15; -if(!is_dir($webRoot . '/feeds/opds/subjects')){ - mkdir($webRoot . '/feeds/opds/subjects'); -} +$dirs = [ '/feeds/opds/subjects', '/feeds/rss/subjects', '/feeds/atom/subjects', + '/feeds/opds/collections', '/feeds/rss/collections', '/feeds/atom/collections', + '/feeds/opds/authors', '/feeds/rss/authors', '/feeds/atom/authors' + ]; -if(!is_dir($webRoot . '/feeds/rss/subjects')){ - mkdir($webRoot . '/feeds/rss/subjects'); -} - -if(!is_dir($webRoot . '/feeds/atom/subjects')){ - mkdir($webRoot . '/feeds/atom/subjects'); +foreach($dirs as $dir){ + if(!is_dir($webRoot . $dir)){ + mkdir($webRoot . $dir); + } } // Iterate over all ebooks to build the various feeds foreach(Library::GetEbooksFromFilesystem($webRoot) as $ebook){ - $allEbooks[$ebook->Updated->format('Y-m-d\TH:i:s\Z') . ' ' . $ebook->Identifier] = $ebook; - $newestEbooks[$ebook->Created->format('Y-m-d\TH:i:s\Z') . ' ' . $ebook->Identifier] = $ebook; + $allEbooks[] = $ebook; + $newestEbooks[] = $ebook; foreach($ebook->Tags as $tag){ - // Add the book's subjects to the main subjects list - if(!in_array($tag->Name, $subjects)){ - $subjects[] = $tag->Name; - } - - // Sort this ebook by subject - $ebooksBySubject[$tag->Name][$ebook->Created->format('Y-m-d\TH:i:s\Z') . ' ' . $ebook->Identifier] = $ebook; + $urlName = Formatter::MakeUrlSafe($tag->Name); + $ebooksBySubject[$urlName][] = $ebook; + $subjects[$urlName] = ['id' => $urlName, 'name' => $tag->Name, 'sortedname' => $tag->Name]; } + + foreach($ebook->Collections as $collection){ + $urlName = Formatter::MakeUrlSafe($collection->Name); + $ebooksByCollection[$urlName][] = $ebook; + $collections[$urlName] = ['id' => $urlName, 'name' => $collection->Name, 'sortedname' => $collection->GetSortedName()]; + } + + $authorsUrl = preg_replace('|^/ebooks/|', '', $ebook->AuthorsUrl); + $ebooksByAuthor[$authorsUrl][] = $ebook; + $authors[$authorsUrl] = ['id' => $authorsUrl, 'name' => strip_tags($ebook->AuthorsHtml), 'sortedname' => $ebook->Authors[0]->SortName]; } -krsort($newestEbooks); +usort($allEbooks, 'SortByUpdatedDesc'); +usort($newestEbooks, function($a, $b){ return $b->Created <=> $a->Created; }); $newestEbooks = array_slice($newestEbooks, 0, $ebooksPerNewestEbooksFeed); $now = new DateTime(); @@ -81,6 +125,20 @@ $opdsRootEntries = [ $now, 'subsection', 'navigation'), + new OpdsNavigationEntry( + 'Standard Ebooks by Collection', + 'Browse Standard Ebooks by collection.', + '/feeds/opds/collections', + $now, + 'subsection', + 'navigation'), + new OpdsNavigationEntry( + 'Standard Ebooks by Author', + 'Browse Standard Ebooks by author.', + '/feeds/opds/authors', + $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.', @@ -91,64 +149,85 @@ $opdsRootEntries = [ ]; $opdsRoot = new OpdsNavigationFeed('Standard Ebooks', 'The Standard Ebooks catalog.', '/feeds/opds', $webRoot . '/feeds/opds/index.xml', $opdsRootEntries, null); -SaveFeed($opdsRoot, $force, $now); +SaveFeed($opdsRoot, $force, null, null, $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.', '/feeds/opds/subjects/' . Formatter::MakeUrlSafe($subject), $now, 'subsection', 'navigation'); -} -$subjectsFeed = new OpdsNavigationFeed('Standard Ebooks by Subject', 'Browse Standard Ebooks by subject.', '/feeds/opds/subjects', $webRoot . '/feeds/opds/subjects/index.xml', $subjectNavigationEntries, $opdsRoot); -$subjectsFeed->Subtitle = 'Browse Standard Ebooks by subject.'; -SaveFeed($subjectsFeed, $force, $now); +// Create the Subjects feeds +CreateOpdsCollectionFeed('subject', '/feeds/opds/subjects', 'Standard Ebooks in the “%s” subject, most-recently-released first.', $subjects, $ebooksBySubject, $now, $webRoot, $opdsRoot, $force); -// Now generate each individual subject feed -foreach($subjectNavigationEntries as $subjectNavigationEntry){ - krsort($ebooksBySubject[$subjectNavigationEntry->Title]); - $subjectFeed = new OpdsAcquisitionFeed($subjectNavigationEntry->Title . ' Ebooks', $subjectNavigationEntry->Description, '/feeds/opds/subjects/' . Formatter::MakeUrlSafe($subjectNavigationEntry->Title), $webRoot . '/feeds/opds/subjects/' . Formatter::MakeUrlSafe($subjectNavigationEntry->Title) . '.xml', $ebooksBySubject[$subjectNavigationEntry->Title], $subjectsFeed); - SaveFeed($subjectFeed, $force, $now); -} +// Create the Collections feeds +CreateOpdsCollectionFeed('collection', '/feeds/opds/collections', 'Standard Ebooks in the “%s” collection, most-recently-released first.', $collections, $ebooksByCollection, $now, $webRoot, $opdsRoot, $force); -// Create the 'all' feed -krsort($allEbooks); +// Create the Author feeds +CreateOpdsCollectionFeed('author', '/feeds/opds/authors', 'Standard Ebooks by %s, most-recently-released first.', $authors, $ebooksByAuthor, $now, $webRoot, $opdsRoot, $force); + +// Create the All feed $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', $webRoot . '/feeds/opds/all.xml', $allEbooks, $opdsRoot, true); -SaveFeed($allFeed, $force, $now); +SaveFeed($allFeed, $force, null, null, $now); -// Create the 'newest' feed +// Create the Newest feed $newestFeed = new OpdsAcquisitionFeed('Newest Standard Ebooks', 'The ' . number_format($ebooksPerNewestEbooksFeed) . ' latest Standard Ebooks, most-recently-released first.', '/feeds/opds/new-releases', $webRoot . '/feeds/opds/new-releases.xml', $newestEbooks, $opdsRoot); -SaveFeed($newestFeed, $force, $now); +SaveFeed($newestFeed, $force, null, null, $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.', '/feeds/rss/new-releases', $webRoot . '/feeds/rss/new-releases.xml', $newestEbooks); -SaveFeed($newestRssFeed, $force); -// Create the 'all' feed +// Create RSS/Atom feeds + +// Create the RSS All feed $allRssFeed = new RssFeed('Standard Ebooks - All Ebooks', 'All Standard Ebooks, most-recently-released first.', '/feeds/rss/all', $webRoot . '/feeds/rss/all.xml', $allEbooks); -SaveFeed($allRssFeed, $force); +SaveFeed($allRssFeed, $force, null, null); -// 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.', '/feeds/rss/subjects/' . Formatter::MakeUrlSafe((string)$subject), $webRoot . '/feeds/rss/subjects/' . Formatter::MakeUrlSafe((string)$subject) . '.xml', $ebooks); - SaveFeed($subjectRssFeed, $force); -} +// Create the RSS Newest feed +$newestRssFeed = new RssFeed('Standard Ebooks - Newest Ebooks', 'The ' . number_format($ebooksPerNewestEbooksFeed) . ' latest Standard Ebooks, most-recently-released first.', '/feeds/rss/new-releases', $webRoot . '/feeds/rss/new-releases.xml', $newestEbooks); +SaveFeed($newestRssFeed, $force, null, null); -// 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.', '/feeds/atom/new-releases', $webRoot . '/feeds/atom/new-releases.xml', $newestEbooks); -SaveFeed($newestAtomFeed, $force, $now); - -// Create the 'all' feed +// Create the Atom All feed $allAtomFeed = new AtomFeed('Standard Ebooks - All Ebooks', 'All Standard Ebooks, most-recently-released first.', '/feeds/atom/all', $webRoot . '/feeds/atom/all.xml', $allEbooks); -SaveFeed($allAtomFeed, $force, $now); +SaveFeed($allAtomFeed, $force, null, null, $now); + +// Create the Atom Newest feed +$newestAtomFeed = new AtomFeed('Standard Ebooks - Newest Ebooks', 'The ' . number_format($ebooksPerNewestEbooksFeed) . ' latest Standard Ebooks, most-recently-released first.', '/feeds/atom/new-releases', $webRoot . '/feeds/atom/new-releases.xml', $newestEbooks); +SaveFeed($newestAtomFeed, $force, null, null, $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.', '/feeds/atom/subjects/' . Formatter::MakeUrlSafe((string)$subject), $webRoot . '/feeds/atom/subjects/' . Formatter::MakeUrlSafe((string)$subject) . '.xml', $ebooks); - SaveFeed($subjectAtomFeed, $force, $now); + usort($ebooks, 'SortByUpdatedDesc'); + + $title = 'Standard Ebooks - ' . $subjects[$subject]['name'] . ' Ebooks'; + $subtitle = 'Standard Ebooks in the “' . strtolower($subjects[$subject]['name']) . '” subject, most-recently-released first.'; + + $subjectRssFeed = new RssFeed($title, $subtitle, '/feeds/rss/subjects/' . Formatter::MakeUrlSafe($subject), $webRoot . '/feeds/rss/subjects/' . Formatter::MakeUrlSafe($subject) . '.xml', $ebooks); + SaveFeed($subjectRssFeed, $force, $subjects[$subject]['name'], $subjects[$subject]['sortedname']); + + $subjectAtomFeed = new AtomFeed($title, $subtitle, '/feeds/atom/subjects/' . Formatter::MakeUrlSafe($subject), $webRoot . '/feeds/atom/subjects/' . Formatter::MakeUrlSafe($subject) . '.xml', $ebooks); + SaveFeed($subjectAtomFeed, $force, $subjects[$subject]['name'], $subjects[$subject]['sortedname'], $now); +} + +// Generate each individual collection feed +foreach($ebooksByCollection as $collection => $ebooks){ + usort($ebooks, 'SortByUpdatedDesc'); + + $titleName = preg_replace('/^The /ius', '', $collections[$collection]['name']); + + $title ='Standard Ebooks - Ebooks in the ' . $titleName . ' collection'; + $subtitle = 'Standard Ebooks in the ' . $titleName . ' collection, most-recently-released first.'; + + $collectionRssFeed = new RssFeed($title, $subtitle, '/feeds/rss/collections/' . Formatter::MakeUrlSafe($collection), $webRoot . '/feeds/rss/collections/' . Formatter::MakeUrlSafe($collection) . '.xml', $ebooks); + SaveFeed($collectionRssFeed, $force, $collections[$collection]['name'], $collections[$collection]['sortedname']); + + $collectionAtomFeed = new AtomFeed($title, $subtitle, '/feeds/atom/collections/' . Formatter::MakeUrlSafe($collection), $webRoot . '/feeds/atom/collections/' . Formatter::MakeUrlSafe($collection) . '.xml', $ebooks); + SaveFeed($collectionAtomFeed, $force, $collections[$collection]['name'], $collections[$collection]['sortedname'], $now); +} + +// Generate each individual author feed +foreach($ebooksByAuthor as $collection => $ebooks){ + usort($ebooks, 'SortByUpdatedDesc'); + + $title = 'Standard Ebooks - Ebooks by ' . $authors[$collection]['name']; + $subtitle = 'Standard Ebooks by ' . $authors[$collection]['name'] . ', most-recently-released first.'; + + $collectionRssFeed = new RssFeed($title, $subtitle, '/feeds/rss/authors/' . $authors[$collection]['id'], $webRoot . '/feeds/rss/authors/' . $authors[$collection]['id'] . '.xml', $ebooks); + SaveFeed($collectionRssFeed, $force, $authors[$collection]['name'], $authors[$collection]['sortedname']); + + $collectionAtomFeed = new AtomFeed($title, $subtitle, '/feeds/atom/authors/' . $authors[$collection]['id'], $webRoot . '/feeds/atom/authors/' . $authors[$collection]['id'] . '.xml', $ebooks); + SaveFeed($collectionAtomFeed, $force, $authors[$collection]['name'], $authors[$collection]['sortedname'], $now); } -?> diff --git a/templates/FeedHowTo.php b/templates/FeedHowTo.php index 5238671f..b5da1966 100644 --- a/templates/FeedHowTo.php +++ b/templates/FeedHowTo.php @@ -2,6 +2,7 @@

Accessing the feeds

Our New Releases feeds are accessible by the public. Access to our other, more detailed feeds is available to our Patrons Circle supporters and our corporate sponsors.

If you’re a Patrons Circle member, when prompted enter your email address and leave the password field blank to access a feed.

+

Access for individuals

+ diff --git a/www/bulk-downloads/collection.php b/www/bulk-downloads/collection.php index 23561c63..3661ee02 100644 --- a/www/bulk-downloads/collection.php +++ b/www/bulk-downloads/collection.php @@ -8,7 +8,7 @@ $canDownload = false; $name = HttpInput::Str(GET, 'name', false) ?? ''; if($name != 'authors' && $name != 'collections' && $name != 'subjects' && $name != 'months'){ - $name = 'subjects'; + Template::Emit404(); } if($GLOBALS['User'] !== null && $GLOBALS['User']->Benefits->CanBulkDownload){ diff --git a/www/feeds/atom/index.php b/www/feeds/atom/index.php index 20c6abc3..cca73b7e 100644 --- a/www/feeds/atom/index.php +++ b/www/feeds/atom/index.php @@ -17,21 +17,24 @@ require_once('Core.php');

The fifteen latest Standard Ebooks, most-recently-released first.

  • -

    All ebooks

    -

    /feeds/atom/all

    +

    All ebooks

    +

    https://Email) ?>@/feeds/atom/all

    All Standard Ebooks, most-recently-released first.

  • -
    -

    Ebooks by subject

    +
    +

    Feeds by topic

    diff --git a/www/feeds/atom/search.php b/www/feeds/atom/search.php index 5a32d511..4140b162 100644 --- a/www/feeds/atom/search.php +++ b/www/feeds/atom/search.php @@ -16,7 +16,7 @@ catch(\Exception $ex){ include(WEB_ROOT . '/404.php'); exit(); } -print("\n\n"); +print("\n\n"); ?> /feeds/atom/all?query= diff --git a/www/feeds/atom/subjects/index.php b/www/feeds/atom/subjects/index.php deleted file mode 100644 index bf837b12..00000000 --- a/www/feeds/atom/subjects/index.php +++ /dev/null @@ -1,22 +0,0 @@ - 'Atom 1.0 Ebook Feeds by Subject', 'description' => 'A list of available Atom 1.0 feeds of Standard Ebooks ebooks by subject.']) ?> -
    -
    -

    Atom 1.0 Ebook Feeds by Subject

    - -
    -

    Ebooks by subject

    -
      - -
    • -

      -

      /feeds/atom/subjects/

      -
    • - -
    -
    -
    -
    - diff --git a/www/feeds/collection.php b/www/feeds/collection.php new file mode 100644 index 00000000..c272ccd0 --- /dev/null +++ b/www/feeds/collection.php @@ -0,0 +1,79 @@ +Url = '/feeds/' . $type . '/' . $name . '/' . basename($file, '.xml'); + + $obj->Label = exec('attr -g se-label ' . escapeshellarg($file)) ?: null; + if($obj->Label == null){ + $obj->Label = basename($file, '.xml'); + } + + $obj->LabelSort = exec('attr -g se-label-sort ' . escapeshellarg($file)) ?: null; + if($obj->LabelSort == null){ + $obj->LabelSort = basename($file, '.xml'); + } + + $feeds[] = $obj; + } + + $collator = Collator::create('en_US'); // Used for sorting letters with diacritics like in author names + if($collator !== null){ + usort($feeds, function($a, $b) use($collator){ return $collator->compare($a->LabelSort, $b->LabelSort); }); + } + + apcu_store('feeds-index-' . $type . '-' . $name, $feeds, 43200); // 12 hours +} +?> $ucType . ' Ebook Feeds by ' . $ucTitle, 'description' => 'A list of available ' . $ucType . ' feeds of Standard Ebooks ebooks by ' . $lcTitle . '.']) ?> +
    +
    +

    Ebook Feeds by

    + +
    +

    Ebooks by

    +
      + +
    • +

      Label) ?>

      +

      https://Email) ?>@Url) ?>

      +
    • + +
    +
    +
    +
    + diff --git a/www/feeds/index.php b/www/feeds/index.php index d4b303c7..c61b66f5 100644 --- a/www/feeds/index.php +++ b/www/feeds/index.php @@ -18,8 +18,8 @@ require_once('Core.php');

    They’re 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.

    diff --git a/www/feeds/opds/search.php b/www/feeds/opds/search.php index c9c06695..ad9467e8 100644 --- a/www/feeds/opds/search.php +++ b/www/feeds/opds/search.php @@ -15,7 +15,7 @@ catch(\Exception $ex){ http_response_code(500); exit(); } -print("\n\n"); +print("\n\n"); ?> /feeds/opds/all?query= diff --git a/www/feeds/rss/index.php b/www/feeds/rss/index.php index 118f88ba..2d801d6c 100644 --- a/www/feeds/rss/index.php +++ b/www/feeds/rss/index.php @@ -8,7 +8,7 @@ require_once('Core.php');

    RSS feeds are the predecessors of Atom feeds. They contain less information than Atom feeds, but might be better supported by some news readers.

    -

    General Feeds

    +

    General feeds

    • New releases (Public)

      @@ -22,15 +22,18 @@ require_once('Core.php');
    -
    -

    Ebooks by subject

    +
    +

    Feeds by topic

    diff --git a/www/feeds/rss/search.php b/www/feeds/rss/search.php index 57bf5665..0650af4d 100644 --- a/www/feeds/rss/search.php +++ b/www/feeds/rss/search.php @@ -16,7 +16,7 @@ catch(\Exception $ex){ include(WEB_ROOT . '/404.php'); exit(); } -print("\n\n"); +print("\n\n"); ?> diff --git a/www/feeds/rss/subjects/index.php b/www/feeds/rss/subjects/index.php deleted file mode 100644 index 47dc11e5..00000000 --- a/www/feeds/rss/subjects/index.php +++ /dev/null @@ -1,22 +0,0 @@ - 'RSS 2.0 Ebook Feeds by Subject', 'description' => 'A list of available RSS 2.0 feeds of Standard Ebooks ebooks by subject.']) ?> -
    -
    -

    RSS 2.0 Ebook Feeds by Subject

    - -
    -

    Ebooks by subject

    -
      - -
    • -

      -

      /feeds/rss/subjects/

      -
    • - -
    -
    -
    -
    -