$longopts = array("webroot:", "weburl:");
$options = getopt("", $longopts);
$webRoot = $options["webroot"] ?? "/standardebooks.org/web";
$webUrl = $options["weburl"] ?? "https://standardebooks.org";
$updatedTimestamp = gmdate('Y-m-d\TH:i:s\Z');
$contentFiles = explode("\n", trim(shell_exec('find ' . escapeshellarg($webRoot . '/www/ebooks/') . ' -name "content.opf" | sort') ?? ''));
$sortedContentFiles = [];
foreach($contentFiles as $path){
if($path == '')
continue;
$xml = new SimpleXMLElement(str_replace('xmlns=', 'ns=', file_get_contents($path) ?: ''));
$xml->registerXPathNamespace('dc', 'http://purl.org/dc/elements/1.1/');
$updated = $xml->xpath('/package/metadata/meta[@property="dcterms:modified"]') ?: [];
if($updated !== false && sizeof($updated) > 0){
$sortedContentFiles[(string)$updated[0]] = $xml;
}
}
krsort($sortedContentFiles);
ob_start();
print("\n");
/* Notes:
- *All* OPDS feeds must contain a rel="crawlable" link pointing to the /opds/all feed
- The element is required to note this as a "Complete Acquisition Feeds"; see https://specs.opds.io/opds-1.2#25-complete-acquisition-feeds
*/
?>
= $webUrl ?>/opds/all
All Standard Ebooks
Free and liberated ebooks, carefully produced for the true book lover.
= $webUrl ?>/images/logo.png
= $updatedTimestamp ?>
Standard Ebooks
= $webUrl ?>
foreach($sortedContentFiles as $xml){
$authors = array();
$temp = $xml->xpath('/package/metadata/dc:identifier') ?: [];
$url = preg_replace('/^url:/ius', '', (string)array_shift($temp)) ?? '';
$url = preg_replace('/^https:\/\/standardebooks.org/ius', $webUrl, $url) ?? '';
$relativeUrl = preg_replace('/^' . preg_quote($webUrl, '/') . '/ius', '', $url) ?? '';
$temp = $xml->xpath('/package/metadata/dc:title') ?: [];
$title = array_shift($temp);
$temp = $xml->xpath('/package/metadata/meta[@property="se:long-description"]') ?: [];
$longDescription = array_shift($temp);
$authors = $xml->xpath('/package/metadata/dc:creator') ?: [];
$temp = $xml->xpath('/package/metadata/dc:date') ?: [];
$published = array_shift($temp);
$temp = $xml->xpath('/package/metadata/dc:language') ?: [];
$language = array_shift($temp);
$temp = $xml->xpath('/package/metadata/meta[@property="dcterms:modified"]') ?: [];
$modified = array_shift($temp);
$temp = $xml->xpath('/package/metadata/dc:description') ?: [];
$description = array_shift($temp);
$subjects = $xml->xpath('/package/metadata/dc:subject') ?: [];
$sources = $xml->xpath('/package/metadata/dc:source') ?: [];
$filesystemPath = preg_replace('/\/src\/epub\/content.opf$/ius', '', $path) ?? '';
$temp = glob($filesystemPath . '/dist/*.epub');
$epubFilename = preg_replace('/(\|\.epub)/ius', '', preg_replace('/.+\//ius', '', array_shift($temp) ?? '') ?? '') ?? '';
$temp = glob($filesystemPath . '/dist/*.azw3');
$kindleFilename = preg_replace('/.+\//ius', '', array_shift($temp) ?? '') ?? '';
?>
= $url ?>
= $title ?>
foreach($authors as $author){
$id = '';
if($author->attributes() !== null){
$id = $author->attributes()->id;
}
$temp = $xml->xpath('/package/metadata/meta[@property="se:url.encyclopedia.wikipedia"][@refines="#' . $id . '"]') ?: [];
$wikiUrl = array_shift($temp);
$temp = $xml->xpath('/package/metadata/meta[@property="se:name.person.full-name"][@refines="#' . $id . '"]') ?: [];
$fullName = array_shift($temp);
$temp = $xml->xpath('/package/metadata/meta[@property="se:url.authority.nacoaf"][@refines="#' . $id . '"]') ?: [];
$nacoafLink = array_shift($temp);
?>
= $author ?>
if($wikiUrl !== null){ ?>= $wikiUrl ?> } ?>
if($fullName !== null){ ?>= $fullName ?> } ?>
if($nacoafLink !== null){ ?>= $nacoafLink ?> } ?>
} ?>
= $published ?>
= $published ?>
= $modified ?>
= $language ?>
Standard Ebooks
foreach($sources as $source){ ?>
= $source ?>
} ?>
Public domain in the United States; original content released to the public domain via the Creative Commons CC0 1.0 Universal Public Domain Dedication
= htmlspecialchars($description, ENT_QUOTES, 'UTF-8') ?>
= $longDescription ?>
foreach($subjects as $subject){ ?>
} ?>
} ?>
// Print the "all feed" to file
$feed = ob_get_contents();
ob_end_clean();
$tempFilename = tempnam('/tmp/', 'se-opds-');
file_put_contents($tempFilename, $feed);
exec('se clean ' . escapeshellarg($tempFilename));
// If the feed has changed compared to the version currently on disk, copy our new version over
// and update the updated timestamp in the master opds index.
try{
if(filesize($webRoot . '/www/opds/all.xml') !== filesize($tempFilename)){
$oldFeed = file_get_contents($webRoot . '/www/opds/all.xml');
$newFeed = file_get_contents($tempFilename);
if($oldFeed != $newFeed){
file_put_contents($webRoot . '/www/opds/all.xml', $newFeed);
// Update the index feed with the last updated timestamp
$xml = new SimpleXMLElement(str_replace('xmlns=', 'ns=', file_get_contents($webRoot . '/www/opds/index.xml')));
$xml->registerXPathNamespace('dc', 'http://purl.org/dc/elements/1.1/');
$xml->registerXPathNamespace('schema', 'http://schema.org/');
$allUpdated = $xml->xpath('/feed/entry[id="https://standardebooks.org/opds/all"]/updated')[0];
$allUpdated[0] = $updatedTimestamp;
file_put_contents($webRoot . '/www/opds/index.xml', str_replace(" ns=", " xmlns=", $xml->asXml()));
exec('se clean ' . escapeshellarg($webRoot) . '/www/opds/index.xml');
}
}
}
catch(Exception $ex){
rename($tempFilename, $webRoot . '/www/opds/all.xml');
}
unlink($tempFilename);
?>