mirror of
https://github.com/standardebooks/web.git
synced 2025-07-12 09:32:24 -04:00
Move feeds behind Patrons Circle login
This commit is contained in:
parent
0a32b295b0
commit
6c603016bd
20 changed files with 367 additions and 183 deletions
|
@ -6,7 +6,7 @@ PHP 7+ is required.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
# Install Apache, PHP, PHP-FPM, and various other dependencies.
|
# Install Apache, PHP, PHP-FPM, and various other dependencies.
|
||||||
sudo apt install -y git composer php-fpm php-cli php-gd php-xml php-apcu php-mbstring php-intl php-curl php-zip apache2 apache2-utils libfcgi0ldbl task-spooler ipv6calc mariadb-server
|
sudo apt install -y git composer php-fpm php-cli php-gd php-xml php-apcu php-mbstring php-intl php-curl php-zip apache2 apache2-utils libfcgi0ldbl task-spooler ipv6calc mariadb-server libaprutil1-dbd-mysql
|
||||||
|
|
||||||
# Create the site root and logs root and clone this repo into it.
|
# Create the site root and logs root and clone this repo into it.
|
||||||
sudo mkdir /standardebooks.org/
|
sudo mkdir /standardebooks.org/
|
||||||
|
@ -26,7 +26,7 @@ echo -e "127.0.0.1\tstandardebooks.test" | sudo tee -a /etc/hosts
|
||||||
openssl req -x509 -nodes -days 99999 -newkey rsa:4096 -subj "/CN=standardebooks.test" -keyout /standardebooks.org/web/config/ssl/standardebooks.test.key -sha256 -out /standardebooks.org/web/config/ssl/standardebooks.test.crt
|
openssl req -x509 -nodes -days 99999 -newkey rsa:4096 -subj "/CN=standardebooks.test" -keyout /standardebooks.org/web/config/ssl/standardebooks.test.key -sha256 -out /standardebooks.org/web/config/ssl/standardebooks.test.crt
|
||||||
|
|
||||||
# Enable the necessary Apache modules.
|
# Enable the necessary Apache modules.
|
||||||
sudo a2enmod headers expires ssl rewrite proxy proxy_fcgi
|
sudo a2enmod headers expires ssl rewrite proxy proxy_fcgi authn_dbd
|
||||||
|
|
||||||
# Link and enable the SE Apache configuration file.
|
# Link and enable the SE Apache configuration file.
|
||||||
sudo ln -s /standardebooks.org/web/config/apache/standardebooks.test.conf /etc/apache2/sites-available/
|
sudo ln -s /standardebooks.org/web/config/apache/standardebooks.test.conf /etc/apache2/sites-available/
|
||||||
|
|
|
@ -50,6 +50,23 @@ SSLStaplingReturnResponderErrors off
|
||||||
Define domain standardebooks.org
|
Define domain standardebooks.org
|
||||||
Define webroot /standardebooks.org/web
|
Define webroot /standardebooks.org/web
|
||||||
|
|
||||||
|
<VirtualHost *:80>
|
||||||
|
ServerName standardebooks.com
|
||||||
|
ServerAlias www.standardebooks.com
|
||||||
|
RedirectPermanent / https://${domain}/
|
||||||
|
</VirtualHost>
|
||||||
|
|
||||||
|
<VirtualHost *:443>
|
||||||
|
ServerName standardebooks.com
|
||||||
|
ServerAlias www.standardebooks.com
|
||||||
|
RedirectPermanent / https://${domain}/
|
||||||
|
|
||||||
|
SSLEngine on
|
||||||
|
SSLCertificateFile /etc/letsencrypt/live/standardebooks.com/fullchain.pem
|
||||||
|
SSLCertificateKeyFile /etc/letsencrypt/live/standardebooks.com/privkey.pem
|
||||||
|
Header always set Strict-Transport-Security "max-age=15768000"
|
||||||
|
</VirtualHost>
|
||||||
|
|
||||||
<VirtualHost *:80>
|
<VirtualHost *:80>
|
||||||
ServerName ${domain}
|
ServerName ${domain}
|
||||||
ServerAlias www.${domain}
|
ServerAlias www.${domain}
|
||||||
|
@ -72,7 +89,7 @@ Define webroot /standardebooks.org/web
|
||||||
Header always set Strict-Transport-Security "max-age=15768000"
|
Header always set Strict-Transport-Security "max-age=15768000"
|
||||||
Header set Content-Security-Policy "default-src 'self';"
|
Header set Content-Security-Policy "default-src 'self';"
|
||||||
|
|
||||||
<Directory ${webroot}/www/>
|
<Directory "${webroot}/www/">
|
||||||
# Disable .htaccess files
|
# Disable .htaccess files
|
||||||
AllowOverride none
|
AllowOverride none
|
||||||
|
|
||||||
|
@ -88,43 +105,31 @@ Define webroot /standardebooks.org/web
|
||||||
|
|
||||||
AddType application/x-mobi8-ebook .azw3
|
AddType application/x-mobi8-ebook .azw3
|
||||||
|
|
||||||
<Location ~ ^/ebooks/.+?/downloads/.+$>
|
<LocationMatch "^/ebooks/.+?/downloads/.+$">
|
||||||
# Serve distributables using the "download" dialog instead of opening in-browser
|
# Serve distributables using the "download" dialog instead of opening in-browser
|
||||||
# Note: the trailing e in the Header directive is required
|
# Note: the trailing e in the Header directive is required
|
||||||
# In modern browsers this is handled with the a@download attribute, we keep this here for compatibility
|
# In modern browsers this is handled with the a@download attribute, we keep this here for compatibility
|
||||||
SetEnvIf Request_URI ^/ebooks/.+?/downloads/(.+)$ FILENAME=$1
|
SetEnvIf Request_URI ^/ebooks/.+?/downloads/(.+)$ FILENAME=$1
|
||||||
Header set Content-Disposition "attachment; filename=%{FILENAME}e"
|
Header set Content-Disposition "attachment; filename=%{FILENAME}e"
|
||||||
</Location>
|
</LocationMatch>
|
||||||
|
|
||||||
# We explicitly set the content-type for items in the /vocab/ directory, because Apache doesn't set it for us,
|
# We explicitly set the content-type for items in the /vocab/ directory, because Apache doesn't set it for us,
|
||||||
# and we need a content-type header when using the "nosniff" header. See https://bugzilla.mozilla.org/show_bug.cgi?id=1547076
|
# and we need a content-type header when using the "nosniff" header. See https://bugzilla.mozilla.org/show_bug.cgi?id=1547076
|
||||||
<Location ~ ^/vocab/.+$>
|
<LocationMatch "^/vocab/.+$">
|
||||||
Header set Content-Type "text/plain"
|
Header set Content-Type "text/plain"
|
||||||
</location>
|
</LocationMatch>
|
||||||
|
|
||||||
<Location ~ ^/feeds/opds>
|
|
||||||
DirectoryIndex index.xml
|
|
||||||
</location>
|
|
||||||
|
|
||||||
# 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.
|
|
||||||
<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
|
# Enable HTTP CORS so that browser-based readers like Readium can access opds and ebooks
|
||||||
# Allow fonts for newsletter emails
|
# Allow fonts for newsletter emails
|
||||||
# See https://github.com/standardebooks/tools/issues/2
|
# See https://github.com/standardebooks/tools/issues/2
|
||||||
<Location ~ /(ebooks|feeds/opds|fonts)>
|
<LocationMatch "/(ebooks|feeds/opds|fonts)">
|
||||||
Header set Access-Control-Allow-Origin "*"
|
Header set Access-Control-Allow-Origin "*"
|
||||||
</Location>
|
</LocationMatch>
|
||||||
|
|
||||||
# We use a different CSP policy for single-page files because our default one doesn't allow inline images or CSS
|
# We use a different CSP policy for single-page files because our default one doesn't allow inline images or CSS
|
||||||
<Location ~ /text/single-page$>
|
<LocationMatch "/text/single-page$">
|
||||||
Header set Content-Security-Policy "default-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline';"
|
Header set Content-Security-Policy "default-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline';"
|
||||||
</Location>
|
</LocationMatch>
|
||||||
|
|
||||||
# Remove www from requests
|
# Remove www from requests
|
||||||
RewriteCond %{HTTP_HOST} ^www\.(.+) [NC]
|
RewriteCond %{HTTP_HOST} ^www\.(.+) [NC]
|
||||||
|
@ -137,13 +142,13 @@ Define webroot /standardebooks.org/web
|
||||||
SetEnv proxy-sendcl 1
|
SetEnv proxy-sendcl 1
|
||||||
|
|
||||||
# Forward all PHP requests to the php-fpm pool for this domain.
|
# Forward all PHP requests to the php-fpm pool for this domain.
|
||||||
<FilesMatch \.php$>
|
<FilesMatch "\.php$">
|
||||||
SetHandler "proxy:unix:/run/php/${domain}.sock|fcgi://${domain}"
|
SetHandler "proxy:unix:/run/php/${domain}.sock|fcgi://${domain}"
|
||||||
Header set Cache-Control "no-store"
|
Header set Cache-Control "no-store"
|
||||||
</FilesMatch>
|
</FilesMatch>
|
||||||
|
|
||||||
# Set some proxy properties.
|
# Set some proxy properties.
|
||||||
<Proxy fcgi://${domain}>
|
<Proxy "fcgi://${domain}">
|
||||||
ProxySet connectiontimeout=5 timeout=240
|
ProxySet connectiontimeout=5 timeout=240
|
||||||
</Proxy>
|
</Proxy>
|
||||||
|
|
||||||
|
@ -190,11 +195,11 @@ Define webroot /standardebooks.org/web
|
||||||
# Redirect index pages
|
# Redirect index pages
|
||||||
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} -d
|
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} -d
|
||||||
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME}/index.php -f
|
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME}/index.php -f
|
||||||
RewriteRule (.*) /$1/index.php
|
RewriteRule (.*) $1/index.php
|
||||||
|
|
||||||
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} -d
|
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} -d
|
||||||
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME}/index.xml -f
|
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME}/index.xml -f
|
||||||
RewriteRule (.*) /$1/index.xml
|
RewriteRule (.*) $1/index.xml
|
||||||
|
|
||||||
# Remove newline characters inserted by accident in some email clients
|
# Remove newline characters inserted by accident in some email clients
|
||||||
RewriteRule ^(.*)\r\n[\ ]?(.*)$ $1$2 [R=301,N]
|
RewriteRule ^(.*)\r\n[\ ]?(.*)$ $1$2 [R=301,N]
|
||||||
|
@ -248,13 +253,6 @@ Define webroot /standardebooks.org/web
|
||||||
RewriteCond %{REQUEST_FILENAME} !^/ebooks/.+?/text.*$
|
RewriteCond %{REQUEST_FILENAME} !^/ebooks/.+?/text.*$
|
||||||
RewriteRule ^/ebooks/([^\.]+?)$ /ebooks/ebook.php?url-path=$1
|
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 ^/feeds/(opds|atom|rss)/all.xml$ /feeds/$1/search.php [QSA]
|
|
||||||
|
|
||||||
# Rewrite old links to feeds
|
|
||||||
RewriteRule ^/(opds|rss|atom)(.*)$ /feeds/$1$2 [R=301,L]
|
|
||||||
|
|
||||||
# Newsletter
|
# Newsletter
|
||||||
RewriteRule ^/newsletter$ /newsletter/subscriptions/new.php [L]
|
RewriteRule ^/newsletter$ /newsletter/subscriptions/new.php [L]
|
||||||
RewriteRule ^/newsletter/subscriptions/([^/\.]+?)$ /newsletter/subscriptions/get.php?uuid=$1 [L]
|
RewriteRule ^/newsletter/subscriptions/([^/\.]+?)$ /newsletter/subscriptions/get.php?uuid=$1 [L]
|
||||||
|
@ -270,21 +268,65 @@ Define webroot /standardebooks.org/web
|
||||||
|
|
||||||
RewriteCond expr "tolower(%{REQUEST_METHOD}) =~ /^post$/"
|
RewriteCond expr "tolower(%{REQUEST_METHOD}) =~ /^post$/"
|
||||||
RewriteRule ^/patrons-circle/polls/([^/\.]+)/votes$ /patrons-circle/polls/votes/post.php?pollurlname=$1 [L]
|
RewriteRule ^/patrons-circle/polls/([^/\.]+)/votes$ /patrons-circle/polls/votes/post.php?pollurlname=$1 [L]
|
||||||
</VirtualHost>
|
|
||||||
|
|
||||||
<VirtualHost *:80>
|
# Feeds
|
||||||
ServerName standardebooks.com
|
# Rewrite old links to feeds
|
||||||
ServerAlias www.standardebooks.com
|
RewriteRule ^/(opds|rss|atom)(.*)$ /feeds/$1$2 [R=301,L]
|
||||||
RedirectPermanent / https://${domain}/
|
|
||||||
</VirtualHost>
|
|
||||||
|
|
||||||
<VirtualHost *:443>
|
# If we ask for /opds/all?query=xyz, rewrite that to the search page.
|
||||||
ServerName standardebooks.com
|
RewriteCond %{QUERY_STRING} \bquery=
|
||||||
ServerAlias www.standardebooks.com
|
RewriteRule ^/feeds/(opds|atom|rss)/all.xml$ /feeds/$1/search.php [QSA]
|
||||||
RedirectPermanent / https://${domain}/
|
|
||||||
|
|
||||||
SSLEngine on
|
# Enable mod_authn_dbd
|
||||||
SSLCertificateFile /etc/letsencrypt/live/standardebooks.com/fullchain.pem
|
DBDriver mysql
|
||||||
SSLCertificateKeyFile /etc/letsencrypt/live/standardebooks.com/privkey.pem
|
DBDParams "dbname=se user=www-data"
|
||||||
Header always set Strict-Transport-Security "max-age=15768000"
|
<DirectoryMatch "^${webroot}/www/feeds/(opds|rss|atom).*">
|
||||||
|
# Enable HTTP Basic auth for feeds
|
||||||
|
AuthType Basic
|
||||||
|
AuthName "Enter your Patrons Circle email address or your API key, and a blank password."
|
||||||
|
Require valid-user
|
||||||
|
ErrorDocument 401 /feeds/401
|
||||||
|
|
||||||
|
# Credentials caching to prevent slamming the DB. socache must be ahead of dbd
|
||||||
|
AuthBasicProvider socache dbd
|
||||||
|
AuthnCacheProvideFor dbd
|
||||||
|
AuthnCacheContext ${domain}
|
||||||
|
|
||||||
|
# mod_authn_dbd SQL query to authenticate a user
|
||||||
|
# The hash is simply the hash of a blank password. We're only interested in the username/API key.
|
||||||
|
# We have to do this tortured query instead of a cleaner one, because the AuthDBDUserPWQuery
|
||||||
|
# function will only replace %s EXACTLY ONCE. We cannot have more than one %s in the query string.
|
||||||
|
AuthDBDUserPWQuery "\
|
||||||
|
select '$apr1$13q1pnGf$vQnIj94BXP1EPdL/4ISba.' from \
|
||||||
|
( \
|
||||||
|
select Email, Uuid from Patrons p inner join Users u using (UserId) where p.Ended is null \
|
||||||
|
union \
|
||||||
|
select Email, Uuid from FeedUsers fu inner join Users u using (UserId) where fu.Ended is null \
|
||||||
|
) x where %s in (Email, Uuid) limit 1 \
|
||||||
|
"
|
||||||
|
|
||||||
|
<FilesMatch "^(style\.php|new-releases\.xml|index\.php|index\.xml)$">
|
||||||
|
# Disable HTTP Basic auth for the feed XSL stylesheet and the new releases feeds
|
||||||
|
Require all granted
|
||||||
|
</FilesMatch>
|
||||||
|
</DirectoryMatch>
|
||||||
|
|
||||||
|
# Emit content-types for OPDS feeds, as some clients require a strictly correct content-type in order to work
|
||||||
|
<DirectoryMatch "^${webroot}/www/feeds/opds">
|
||||||
|
Header set Content-Type "application/atom+xml;profile=opds-catalog;kind=acquisition; charset=utf-8"
|
||||||
|
|
||||||
|
<FilesMatch "^index\.xml$">
|
||||||
|
Header set Content-Type "application/atom+xml;profile=opds-catalog;kind=navigation; charset=utf-8"
|
||||||
|
</FilesMatch>
|
||||||
|
</DirectoryMatch>
|
||||||
|
|
||||||
|
# Emit content-types for RSS/Atom feeds
|
||||||
|
<DirectoryMatch "^${webroot}/www/feeds/(?<feedtype>rss|atom)/.+">
|
||||||
|
# Note the trailing e is required to complete the environmental variable reference
|
||||||
|
Header set Content-Type "application/%{MATCH_FEEDTYPE}e+xml; charset=utf-8"
|
||||||
|
|
||||||
|
<FilesMatch "^index\.php$">
|
||||||
|
Header set Content-Type "application/xhtml+xml; charset=utf-8"
|
||||||
|
</FilesMatch>
|
||||||
|
</DirectoryMatch>
|
||||||
</VirtualHost>
|
</VirtualHost>
|
||||||
|
|
|
@ -71,7 +71,7 @@ Define webroot /standardebooks.org/web
|
||||||
Header always set Strict-Transport-Security "max-age=15768000"
|
Header always set Strict-Transport-Security "max-age=15768000"
|
||||||
Header set Content-Security-Policy "default-src 'self';"
|
Header set Content-Security-Policy "default-src 'self';"
|
||||||
|
|
||||||
<Directory ${webroot}/www/>
|
<Directory "${webroot}/www/">
|
||||||
# Disable .htaccess files
|
# Disable .htaccess files
|
||||||
AllowOverride none
|
AllowOverride none
|
||||||
|
|
||||||
|
@ -87,43 +87,31 @@ Define webroot /standardebooks.org/web
|
||||||
|
|
||||||
AddType application/x-mobi8-ebook .azw3
|
AddType application/x-mobi8-ebook .azw3
|
||||||
|
|
||||||
<Location ~ ^/ebooks/.+?/downloads/.+$>
|
<LocationMatch "^/ebooks/.+?/downloads/.+$">
|
||||||
# Serve distributables using the "download" dialog instead of opening in-browser
|
# Serve distributables using the "download" dialog instead of opening in-browser
|
||||||
# Note: the trailing e in the Header directive is required
|
# Note: the trailing e in the Header directive is required
|
||||||
# In modern browsers this is handled with the a@download attribute, we keep this here for compatibility
|
# In modern browsers this is handled with the a@download attribute, we keep this here for compatibility
|
||||||
SetEnvIf Request_URI ^/ebooks/.+?/downloads/(.+)$ FILENAME=$1
|
SetEnvIf Request_URI ^/ebooks/.+?/downloads/(.+)$ FILENAME=$1
|
||||||
Header set Content-Disposition "attachment; filename=%{FILENAME}e"
|
Header set Content-Disposition "attachment; filename=%{FILENAME}e"
|
||||||
</Location>
|
</LocationMatch>
|
||||||
|
|
||||||
# We explicitly set the content-type for items in the /vocab/ directory, because Apache doesn't set it for us,
|
# We explicitly set the content-type for items in the /vocab/ directory, because Apache doesn't set it for us,
|
||||||
# and we need a content-type header when using the "nosniff" header. See https://bugzilla.mozilla.org/show_bug.cgi?id=1547076
|
# and we need a content-type header when using the "nosniff" header. See https://bugzilla.mozilla.org/show_bug.cgi?id=1547076
|
||||||
<Location ~ ^/vocab/.+$>
|
<LocationMatch "^/vocab/.+$">
|
||||||
Header set Content-Type "text/plain"
|
Header set Content-Type "text/plain"
|
||||||
</location>
|
</LocationMatch>
|
||||||
|
|
||||||
<Location ~ ^/feeds/opds>
|
|
||||||
DirectoryIndex index.xml
|
|
||||||
</location>
|
|
||||||
|
|
||||||
# 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.
|
|
||||||
<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
|
# Enable HTTP CORS so that browser-based readers like Readium can access opds and ebooks
|
||||||
# Allow fonts for newsletter emails
|
# Allow fonts for newsletter emails
|
||||||
# See https://github.com/standardebooks/tools/issues/2
|
# See https://github.com/standardebooks/tools/issues/2
|
||||||
<Location ~ /(ebooks|feeds/opds|fonts)>
|
<LocationMatch "/(ebooks|feeds/opds|fonts)">
|
||||||
Header set Access-Control-Allow-Origin "*"
|
Header set Access-Control-Allow-Origin "*"
|
||||||
</Location>
|
</LocationMatch>
|
||||||
|
|
||||||
# We use a different CSP policy for single-page files because our default one doesn't allow inline images or CSS
|
# We use a different CSP policy for single-page files because our default one doesn't allow inline images or CSS
|
||||||
<Location ~ /text/single-page$>
|
<LocationMatch "/text/single-page$">
|
||||||
Header set Content-Security-Policy "default-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline';"
|
Header set Content-Security-Policy "default-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline';"
|
||||||
</Location>
|
</LocationMatch>
|
||||||
|
|
||||||
# Remove www from requests
|
# Remove www from requests
|
||||||
RewriteCond %{HTTP_HOST} ^www\.(.+) [NC]
|
RewriteCond %{HTTP_HOST} ^www\.(.+) [NC]
|
||||||
|
@ -136,13 +124,13 @@ Define webroot /standardebooks.org/web
|
||||||
SetEnv proxy-sendcl 1
|
SetEnv proxy-sendcl 1
|
||||||
|
|
||||||
# Forward all PHP requests to the php-fpm pool for this domain.
|
# Forward all PHP requests to the php-fpm pool for this domain.
|
||||||
<FilesMatch \.php$>
|
<FilesMatch "\.php$">
|
||||||
SetHandler "proxy:unix:/run/php/${domain}.sock|fcgi://${domain}"
|
SetHandler "proxy:unix:/run/php/${domain}.sock|fcgi://${domain}"
|
||||||
Header set Cache-Control "no-store"
|
Header set Cache-Control "no-store"
|
||||||
</FilesMatch>
|
</FilesMatch>
|
||||||
|
|
||||||
# Set some proxy properties.
|
# Set some proxy properties.
|
||||||
<Proxy fcgi://${domain}>
|
<Proxy "fcgi://${domain}">
|
||||||
ProxySet connectiontimeout=5 timeout=240
|
ProxySet connectiontimeout=5 timeout=240
|
||||||
</Proxy>
|
</Proxy>
|
||||||
|
|
||||||
|
@ -189,11 +177,11 @@ Define webroot /standardebooks.org/web
|
||||||
# Redirect index pages
|
# Redirect index pages
|
||||||
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} -d
|
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} -d
|
||||||
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME}/index.php -f
|
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME}/index.php -f
|
||||||
RewriteRule (.*) /$1/index.php
|
RewriteRule (.*) $1/index.php
|
||||||
|
|
||||||
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} -d
|
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} -d
|
||||||
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME}/index.xml -f
|
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME}/index.xml -f
|
||||||
RewriteRule (.*) /$1/index.xml
|
RewriteRule (.*) $1/index.xml
|
||||||
|
|
||||||
# Remove newline characters inserted by accident in some email clients
|
# Remove newline characters inserted by accident in some email clients
|
||||||
RewriteRule ^(.*)\r\n[\ ]?(.*)$ $1$2 [R=301,N]
|
RewriteRule ^(.*)\r\n[\ ]?(.*)$ $1$2 [R=301,N]
|
||||||
|
@ -247,13 +235,6 @@ Define webroot /standardebooks.org/web
|
||||||
RewriteCond %{REQUEST_FILENAME} !^/ebooks/.+?/text.*$
|
RewriteCond %{REQUEST_FILENAME} !^/ebooks/.+?/text.*$
|
||||||
RewriteRule ^/ebooks/([^\.]+?)$ /ebooks/ebook.php?url-path=$1
|
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 ^/feeds/(opds|atom|rss)/all.xml$ /feeds/$1/search.php [QSA]
|
|
||||||
|
|
||||||
# Rewrite old links to feeds
|
|
||||||
RewriteRule ^/(opds|rss|atom)(.*)$ /feeds/$1$2 [R=301,L]
|
|
||||||
|
|
||||||
# Newsletter
|
# Newsletter
|
||||||
RewriteRule ^/newsletter$ /newsletter/subscriptions/new.php [L]
|
RewriteRule ^/newsletter$ /newsletter/subscriptions/new.php [L]
|
||||||
RewriteRule ^/newsletter/subscriptions/([^/\.]+?)$ /newsletter/subscriptions/get.php?uuid=$1 [L]
|
RewriteRule ^/newsletter/subscriptions/([^/\.]+?)$ /newsletter/subscriptions/get.php?uuid=$1 [L]
|
||||||
|
@ -269,4 +250,65 @@ Define webroot /standardebooks.org/web
|
||||||
|
|
||||||
RewriteCond expr "tolower(%{REQUEST_METHOD}) =~ /^post$/"
|
RewriteCond expr "tolower(%{REQUEST_METHOD}) =~ /^post$/"
|
||||||
RewriteRule ^/patrons-circle/polls/([^/\.]+)/votes$ /patrons-circle/polls/votes/post.php?pollurlname=$1 [L]
|
RewriteRule ^/patrons-circle/polls/([^/\.]+)/votes$ /patrons-circle/polls/votes/post.php?pollurlname=$1 [L]
|
||||||
|
|
||||||
|
# Feeds
|
||||||
|
# Rewrite old links to feeds
|
||||||
|
RewriteRule ^/(opds|rss|atom)(.*)$ /feeds/$1$2 [R=301,L]
|
||||||
|
|
||||||
|
# If we ask for /opds/all?query=xyz, rewrite that to the search page.
|
||||||
|
RewriteCond %{QUERY_STRING} \bquery=
|
||||||
|
RewriteRule ^/feeds/(opds|atom|rss)/all.xml$ /feeds/$1/search.php [QSA]
|
||||||
|
|
||||||
|
# Enable mod_authn_dbd
|
||||||
|
DBDriver mysql
|
||||||
|
DBDParams "dbname=se user=www-data"
|
||||||
|
<DirectoryMatch "^${webroot}/www/feeds/(opds|rss|atom).*">
|
||||||
|
# Enable HTTP Basic auth for feeds
|
||||||
|
AuthType Basic
|
||||||
|
AuthName "Enter your Patrons Circle email address or your API key, and a blank password."
|
||||||
|
Require valid-user
|
||||||
|
ErrorDocument 401 /feeds/401
|
||||||
|
|
||||||
|
# Credentials caching to prevent slamming the DB. socache must be ahead of dbd
|
||||||
|
AuthBasicProvider socache dbd
|
||||||
|
AuthnCacheProvideFor dbd
|
||||||
|
AuthnCacheContext ${domain}
|
||||||
|
|
||||||
|
# mod_authn_dbd SQL query to authenticate a user
|
||||||
|
# The hash is simply the hash of a blank password. We're only interested in the username/API key.
|
||||||
|
# We have to do this tortured query instead of a cleaner one, because the AuthDBDUserPWQuery
|
||||||
|
# function will only replace %s EXACTLY ONCE. We cannot have more than one %s in the query string.
|
||||||
|
AuthDBDUserPWQuery "\
|
||||||
|
select '$apr1$13q1pnGf$vQnIj94BXP1EPdL/4ISba.' from \
|
||||||
|
( \
|
||||||
|
select Email, Uuid from Patrons p inner join Users u using (UserId) where p.Ended is null \
|
||||||
|
union \
|
||||||
|
select Email, Uuid from FeedUsers fu inner join Users u using (UserId) where fu.Ended is null \
|
||||||
|
) x where %s in (Email, Uuid) limit 1 \
|
||||||
|
"
|
||||||
|
|
||||||
|
<FilesMatch "^(style\.php|new-releases\.xml|index\.php|index\.xml)$">
|
||||||
|
# Disable HTTP Basic auth for the feed XSL stylesheet and the new releases feeds
|
||||||
|
Require all granted
|
||||||
|
</FilesMatch>
|
||||||
|
</DirectoryMatch>
|
||||||
|
|
||||||
|
# Emit content-types for OPDS feeds, as some clients require a strictly correct content-type in order to work
|
||||||
|
<DirectoryMatch "^${webroot}/www/feeds/opds">
|
||||||
|
Header set Content-Type "application/atom+xml;profile=opds-catalog;kind=acquisition; charset=utf-8"
|
||||||
|
|
||||||
|
<FilesMatch "^index\.xml$">
|
||||||
|
Header set Content-Type "application/atom+xml;profile=opds-catalog;kind=navigation; charset=utf-8"
|
||||||
|
</FilesMatch>
|
||||||
|
</DirectoryMatch>
|
||||||
|
|
||||||
|
# Emit content-types for RSS/Atom feeds
|
||||||
|
<DirectoryMatch "^${webroot}/www/feeds/(?<feedtype>rss|atom)/.+">
|
||||||
|
# Note the trailing e is required to complete the environmental variable reference
|
||||||
|
Header set Content-Type "application/%{MATCH_FEEDTYPE}e+xml; charset=utf-8"
|
||||||
|
|
||||||
|
<FilesMatch "^index\.php$">
|
||||||
|
Header set Content-Type "application/xhtml+xml; charset=utf-8"
|
||||||
|
</FilesMatch>
|
||||||
|
</DirectoryMatch>
|
||||||
</VirtualHost>
|
</VirtualHost>
|
||||||
|
|
7
config/sql/se/FeedUsers.sql
Normal file
7
config/sql/se/FeedUsers.sql
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
CREATE TABLE `FeedUsers` (
|
||||||
|
`UserId` int(10) unsigned NOT NULL,
|
||||||
|
`Created` datetime NOT NULL,
|
||||||
|
`Ended` datetime DEFAULT NULL,
|
||||||
|
`Notes` text DEFAULT NULL,
|
||||||
|
KEY `idxUserId` (`UserId`,`Ended`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
@ -5,6 +5,6 @@ CREATE TABLE `Patrons` (
|
||||||
`IsSubscribedToEmails` tinyint(1) NOT NULL DEFAULT 1,
|
`IsSubscribedToEmails` tinyint(1) NOT NULL DEFAULT 1,
|
||||||
`Created` datetime NOT NULL,
|
`Created` datetime NOT NULL,
|
||||||
`Ended` datetime DEFAULT NULL,
|
`Ended` datetime DEFAULT NULL,
|
||||||
PRIMARY KEY (`UserId`),
|
KEY `index2` (`IsAnonymous`,`Ended`),
|
||||||
KEY `index2` (`IsAnonymous`,`Ended`)
|
KEY `index1` (`UserId`,`Ended`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
|
@ -107,7 +107,7 @@ $opdsRootEntries = [
|
||||||
'acquisition')
|
'acquisition')
|
||||||
];
|
];
|
||||||
|
|
||||||
$opdsRoot = new OpdsNavigationFeed('Standard Ebooks', 'The navigation root for the Standard Ebooks OPDS feed.', '/feeds/opds', WEB_ROOT . '/feeds/opds/index.xml', $opdsRootEntries, null);
|
$opdsRoot = new OpdsNavigationFeed('Standard Ebooks', 'The Standard Ebooks catalog.', '/feeds/opds', WEB_ROOT . '/feeds/opds/index.xml', $opdsRootEntries, null);
|
||||||
SaveFeed($opdsRoot, $force, $now);
|
SaveFeed($opdsRoot, $force, $now);
|
||||||
|
|
||||||
// Create the subjects navigation document
|
// Create the subjects navigation document
|
||||||
|
|
19
templates/FeedHowTo.php
Normal file
19
templates/FeedHowTo.php
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
<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 supporters in the <a href="/donate#patrons-circle">Patrons Circle</a>.</p>
|
||||||
|
<section id="individuals">
|
||||||
|
<h3>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 you’ve already done that, <a href="/about#editor-in-chief">contact us</a> to enable your access.</p></li>
|
||||||
|
</ul>
|
||||||
|
<p>To access a feed, when prompted enter the email address you used to make your donation or on the S.E. mailing list, and leave the password field blank.</p>
|
||||||
|
</section>
|
||||||
|
<section id="organizations-and-projects">
|
||||||
|
<h3>Organizations and projects</h3>
|
||||||
|
<ul>
|
||||||
|
<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>
|
||||||
|
</section>
|
|
@ -8,7 +8,7 @@ $colorScheme = $_COOKIE['color-scheme'] ?? 'auto';
|
||||||
$xmlDeclaration = $xmlDeclaration ?? true;
|
$xmlDeclaration = $xmlDeclaration ?? true;
|
||||||
|
|
||||||
if($xmlDeclaration){
|
if($xmlDeclaration){
|
||||||
header('content-type: application/xhtml+xml');
|
header('content-type: application/xhtml+xml; charset=utf-8');
|
||||||
print('<?xml version="1.0" encoding="utf-8"?>');
|
print('<?xml version="1.0" encoding="utf-8"?>');
|
||||||
print("\n");
|
print("\n");
|
||||||
print("<!DOCTYPE html>\n");
|
print("<!DOCTYPE html>\n");
|
||||||
|
|
|
@ -32,5 +32,5 @@
|
||||||
<? if(file_exists(WEB_ROOT . $entry->AdvancedEpubUrl)){ ?><link href="<?= SITE_URL . $entry->AdvancedEpubUrl ?>" length="<?= filesize(WEB_ROOT . $entry->AdvancedEpubUrl) ?>" rel="http://opds-spec.org/acquisition/open-access" title="Advanced epub" type="application/epub+zip" /><? } ?>
|
<? if(file_exists(WEB_ROOT . $entry->AdvancedEpubUrl)){ ?><link href="<?= SITE_URL . $entry->AdvancedEpubUrl ?>" length="<?= filesize(WEB_ROOT . $entry->AdvancedEpubUrl) ?>" rel="http://opds-spec.org/acquisition/open-access" title="Advanced epub" type="application/epub+zip" /><? } ?>
|
||||||
<? if(file_exists(WEB_ROOT . $entry->KepubUrl)){ ?><link href="<?= SITE_URL . $entry->KepubUrl ?>" length="<?= filesize(WEB_ROOT . $entry->KepubUrl) ?>" rel="http://opds-spec.org/acquisition/open-access" title="Kobo Kepub epub" type="application/kepub+zip" /><? } ?>
|
<? if(file_exists(WEB_ROOT . $entry->KepubUrl)){ ?><link href="<?= SITE_URL . $entry->KepubUrl ?>" length="<?= filesize(WEB_ROOT . $entry->KepubUrl) ?>" rel="http://opds-spec.org/acquisition/open-access" title="Kobo Kepub epub" type="application/kepub+zip" /><? } ?>
|
||||||
<? if(file_exists(WEB_ROOT . $entry->Azw3Url)){ ?><link href="<?= SITE_URL . $entry->Azw3Url ?>" length="<?= filesize(WEB_ROOT . $entry->Azw3Url) ?>" rel="http://opds-spec.org/acquisition/open-access" title="Amazon Kindle azw3" type="application/x-mobipocket-ebook" /><? } ?>
|
<? if(file_exists(WEB_ROOT . $entry->Azw3Url)){ ?><link href="<?= SITE_URL . $entry->Azw3Url ?>" length="<?= filesize(WEB_ROOT . $entry->Azw3Url) ?>" rel="http://opds-spec.org/acquisition/open-access" title="Amazon Kindle azw3" type="application/x-mobipocket-ebook" /><? } ?>
|
||||||
<? if(file_exists(WEB_ROOT . $entry->TextSinglePageUrl)){ ?><link href="<?= SITE_URL . $entry->TextSinglePageUrl ?>" length="<?= filesize(WEB_ROOT . $entry->TextSinglePageUrl) ?>" rel="http://opds-spec.org/acquisition/open-access" title="XHTML" type="application/xhtml+xml" /><? } ?>
|
<? if(file_exists(WEB_ROOT . $entry->TextSinglePageUrl)){ ?><link href="<?= SITE_URL . $entry->TextSinglePageUrl ?>" length="<?= filesize(WEB_ROOT . $entry->TextSinglePageUrl) ?>" rel="http://opds-spec.org/acquisition/open-access" title="XHTML" type="application/xhtml+xml; charset=utf-8" /><? } ?>
|
||||||
</entry>
|
</entry>
|
||||||
|
|
|
@ -18,11 +18,11 @@ 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/"<? if($isCrawlable){ ?> xmlns:fh="http://purl.org/syndication/history/1.0"<? } ?>>
|
<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>
|
<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 . Formatter::ToPlainXmlText($url) ?>" rel="self" type="application/atom+xml;profile=opds-catalog;kind=acquisition; charset=utf-8"/>
|
||||||
<link href="<?= SITE_URL ?>/feeds/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; charset=utf-8"/>
|
||||||
<link href="<?= SITE_URL ?><?= Formatter::ToPlainXmlText($parentUrl) ?>" rel="up" 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; charset=utf-8"/>
|
||||||
<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 ?>/feeds/opds/all" rel="http://opds-spec.org/crawlable" type="application/atom+xml;profile=opds-catalog;kind=acquisition; charset=utf-8"/>
|
||||||
<link href="<?= SITE_URL ?>/ebooks/opensearch" rel="search" type="application/opensearchdescription+xml"/>
|
<link href="<?= SITE_URL ?>/ebooks/opensearch" rel="search" type="application/opensearchdescription+xml; charset=utf-8"/>
|
||||||
<title><?= Formatter::ToPlainXmlText($title) ?></title>
|
<title><?= Formatter::ToPlainXmlText($title) ?></title>
|
||||||
<? if($subtitle !== null){ ?><subtitle><?= Formatter::ToPlainXmlText($subtitle) ?></subtitle><? } ?>
|
<? if($subtitle !== null){ ?><subtitle><?= Formatter::ToPlainXmlText($subtitle) ?></subtitle><? } ?>
|
||||||
<icon><?= SITE_URL ?>/images/logo.png</icon>
|
<icon><?= SITE_URL ?>/images/logo.png</icon>
|
||||||
|
|
|
@ -9,11 +9,11 @@ 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/">
|
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||||
<id><?= SITE_URL . Formatter::ToPlainXmlText($id) ?></id>
|
<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 . Formatter::ToPlainXmlText($url) ?>" rel="self" type="application/atom+xml;profile=opds-catalog;kind=navigation; charset=utf-8"/>
|
||||||
<link href="<?= SITE_URL ?>/feeds/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; charset=utf-8"/>
|
||||||
<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 ?>/feeds/opds/all" rel="http://opds-spec.org/crawlable" type="application/atom+xml;profile=opds-catalog;kind=acquisition; charset=utf-8"/>
|
||||||
<link href="<?= SITE_URL ?>/ebooks/opensearch" rel="search" type="application/opensearchdescription+xml"/>
|
<link href="<?= SITE_URL ?>/ebooks/opensearch" rel="search" type="application/opensearchdescription+xml; charset=utf-8"/>
|
||||||
<? if($parentUrl !== null){ ?><link href="<?= SITE_URL ?><?= Formatter::ToPlainXmlText($parentUrl) ?>" rel="up" type="application/atom+xml;profile=opds-catalog;kind=navigation"/><? } ?>
|
<? if($parentUrl !== null){ ?><link href="<?= SITE_URL ?><?= Formatter::ToPlainXmlText($parentUrl) ?>" rel="up" type="application/atom+xml;profile=opds-catalog;kind=navigation; charset=utf-8"/><? } ?>
|
||||||
<title><?= Formatter::ToPlainXmlText($title) ?></title>
|
<title><?= Formatter::ToPlainXmlText($title) ?></title>
|
||||||
<? if($subtitle !== null){ ?><subtitle><?= Formatter::ToPlainXmlText($subtitle) ?></subtitle><? } ?>
|
<? if($subtitle !== null){ ?><subtitle><?= Formatter::ToPlainXmlText($subtitle) ?></subtitle><? } ?>
|
||||||
<icon><?= SITE_URL ?>/images/logo.png</icon>
|
<icon><?= SITE_URL ?>/images/logo.png</icon>
|
||||||
|
@ -25,7 +25,7 @@ print("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
|
||||||
<? foreach($entries as $entry){ ?>
|
<? foreach($entries as $entry){ ?>
|
||||||
<entry>
|
<entry>
|
||||||
<title><?= Formatter::ToPlainXmlText($entry->Title) ?></title>
|
<title><?= Formatter::ToPlainXmlText($entry->Title) ?></title>
|
||||||
<link href="<?= SITE_URL . Formatter::ToPlainXmlText($entry->Url) ?>" rel="<?= Formatter::ToPlainXmlText($entry->Rel) ?>" type="application/atom+xml;profile=opds-catalog;kind=<?= $entry->Type ?>"/>
|
<link href="<?= SITE_URL . Formatter::ToPlainXmlText($entry->Url) ?>" rel="<?= Formatter::ToPlainXmlText($entry->Rel) ?>" type="application/atom+xml;profile=opds-catalog;kind=<?= $entry->Type ?>; charset=utf-8"/>
|
||||||
<updated><? if($entry->Updated !== null){ ?><?= $entry->Updated->format('Y-m-d\TH:i:s\Z') ?><? } ?></updated>
|
<updated><? if($entry->Updated !== null){ ?><?= $entry->Updated->format('Y-m-d\TH:i:s\Z') ?><? } ?></updated>
|
||||||
<id><?= Formatter::ToPlainXmlText($entry->Id) ?></id>
|
<id><?= Formatter::ToPlainXmlText($entry->Id) ?></id>
|
||||||
<content type="text"><?= Formatter::ToPlainXmlText($entry->Description) ?></content>
|
<content type="text"><?= Formatter::ToPlainXmlText($entry->Description) ?></content>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
FROM ubuntu:20.04
|
FROM ubuntu:20.04
|
||||||
|
|
||||||
RUN apt-get update
|
RUN apt-get update
|
||||||
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y composer php-fpm php-cli php-gd php-xml php-apcu php-mbstring php-intl apache2 apache2-utils libfcgi0ldbl task-spooler
|
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y composer php-fpm php-cli php-gd php-xml php-apcu php-mbstring php-intl apache2 apache2-utils libfcgi0ldbl task-spooler libaprutil1-dbd-mysql
|
||||||
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y sudo imagemagick openjdk-8-jre python3 pip calibre
|
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y sudo imagemagick openjdk-8-jre python3 pip calibre
|
||||||
RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ RUN sudo usermod -g committers se
|
||||||
RUN mkdir -p /standardebooks.org/web
|
RUN mkdir -p /standardebooks.org/web
|
||||||
RUN mkdir /var/log/local
|
RUN mkdir /var/log/local
|
||||||
|
|
||||||
RUN a2enmod headers expires ssl rewrite proxy proxy_fcgi
|
RUN a2enmod headers expires ssl rewrite proxy proxy_fcgi authn_dbd
|
||||||
|
|
||||||
# Disable opcaching for dynamic PHP reloading
|
# Disable opcaching for dynamic PHP reloading
|
||||||
RUN echo "opcache.enable=0" >> /etc/php/7.4/fpm/php.ini
|
RUN echo "opcache.enable=0" >> /etc/php/7.4/fpm/php.ini
|
||||||
|
|
|
@ -27,15 +27,30 @@ require_once('Core.php');
|
||||||
<h2>Join the Patrons Circle</h2>
|
<h2>Join the Patrons Circle</h2>
|
||||||
<p>Members of the Patrons Circle are steadfast supporters of free, unrestricted, and beautifully presented digital literature. Besides helping support the creation of free, gorgeous ebooks, they also have a direct voice in shaping the future of the Standard Ebooks catalog.</p>
|
<p>Members of the Patrons Circle are steadfast supporters of free, unrestricted, and beautifully presented digital literature. Besides helping support the creation of free, gorgeous ebooks, they also have a direct voice in shaping the future of the Standard Ebooks catalog.</p>
|
||||||
<p><i>Join the Patrons Circle with a donation of $10/month or more, or join for one year with a one-time donation of $100 or more.</i></p>
|
<p><i>Join the Patrons Circle with a donation of $10/month or more, or join for one year with a one-time donation of $100 or more.</i></p>
|
||||||
|
<p>During your time as a member of the Patrons Circle, you get:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<p>Patrons Circle members have their name <a href="/about#patrons-circle">listed on our masthead</a> for the duration of their gift.</p>
|
<p>Your name <a href="/about#patrons-circle">listed on our masthead</a>.</p>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<p>Once per quarter, Patrons Circle members may submit a book for inclusion on our <a href="/contribute/wanted-ebooks">Wanted Ebooks list</a>. (Submissions must conform to our <a href="/contribute/collections-policy">collections policy</a> and are subject to approval.)</p>
|
<p>Access to our various <a href="/feeds">ebook feeds</a>:</p>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<p>Browse and download from the entire Standard Ebooks catalog directly in your ereading app using our <a href="/feeds/opds">OPDS feed</a>.</p>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<p>Get notified of new ebooks in your news client with our <a href="/feeds/atom">Atom</a> or <a href="/feeds/rss">RSS</a> feeds.</p>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<p>Parse and process the feeds to use our ebooks in your personal software projects. (Organizations, see <a href="#corporate-sponsors">corporate sponsorship</a> instead.)</p>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<p><strong>Periodically, members of the Patrons Circle vote on a selection from our <a href="/contribute/wanted-ebooks">Wanted Ebooks list</a> to choose an ebook for immediate production.</strong> The resulting ebook will be a permanent addition to our <a href="/ebooks">online catalog of free digital literature</a>.</p>
|
<p>The ability to submit a book for inclusion on our <a href="/contribute/wanted-ebooks">Wanted Ebooks list</a>, once per quarter. (Submissions must conform to our <a href="/contribute/collections-policy">collections policy</a> and are subject to approval.)</p>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<p><strong>The right to periodically vote on a selection from our <a href="/contribute/wanted-ebooks">Wanted Ebooks list</a> to choose an ebook for immediate production.</strong> The resulting ebook will be a permanent addition to our <a href="/ebooks">online catalog of free digital literature</a>.</p>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p class="button-row">
|
<p class="button-row">
|
||||||
|
@ -118,13 +133,13 @@ require_once('Core.php');
|
||||||
</section>
|
</section>
|
||||||
<section id="corporate-sponsors">
|
<section id="corporate-sponsors">
|
||||||
<h2>Corporate sponsorships</h2>
|
<h2>Corporate sponsorships</h2>
|
||||||
<p>Sponsorships at the corporate level are a great way to show your organization’s commitment to the support of the literate arts.</p>
|
<p>Sponsorships at the corporate level are a great way to show your organization’s commitment to supporting the literate arts.</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<p>Your organization’s logo and a link will be <a href="/about#corporate-sponsors">listed on our masthead</a>, which is prominently linked to on the Standard Ebooks website’s header and footer.</p>
|
<p>Your organization’s logo and a link will be <a href="/about#corporate-sponsors">listed on our masthead</a>, which is prominently linked to on the Standard Ebooks website’s header and footer.</p>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<p>Get customized <abbr class="acronym">ONIX</abbr>, OPDS, or RSS feeds of our ebook catalog for use by your organization for the duration of your sponsorship.</p>
|
<p>Get access to our OPDS, Atom, and RSS <a href="/feeds">ebook feeds</a> for use by your organization for the duration of your sponsorship. We can also produce different kinds of feeds to meet your needs, like <abbr class="acronym">ONIX</abbr> feeds.</p>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p>To inquire about sponsorship options, contact the <a href="/about#editor-in-chief">Standard Ebooks Editor-in-Chief</a>.</p>
|
<p>To inquire about sponsorship options, contact the <a href="/about#editor-in-chief">Standard Ebooks Editor-in-Chief</a>.</p>
|
||||||
|
|
46
www/feeds/401.php
Normal file
46
www/feeds/401.php
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
<?
|
||||||
|
require_once('Core.php');
|
||||||
|
|
||||||
|
use function Safe\preg_match;
|
||||||
|
|
||||||
|
$type = '';
|
||||||
|
preg_match('/^\/feeds\/(opds|rss|atom)/ius', $_SERVER['REQUEST_URI'], $matches);
|
||||||
|
|
||||||
|
if(sizeof($matches) > 0){
|
||||||
|
$type = $matches[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
$title = 'Standard Ebooks Ebook Feeds';
|
||||||
|
if($type == 'opds'){
|
||||||
|
$title = 'The Standard Ebooks OPDS Feed';
|
||||||
|
}
|
||||||
|
|
||||||
|
if($type == 'rss'){
|
||||||
|
$title = 'Standard Ebooks RSS Feeds';
|
||||||
|
}
|
||||||
|
|
||||||
|
if($type == 'atom'){
|
||||||
|
$title = 'Standard Ebooks Atom Feeds';
|
||||||
|
}
|
||||||
|
|
||||||
|
?><?= Template::Header(['title' => 'The Standard Ebooks OPDS feed', 'highlight' => '', 'description' => 'Get access to the Standard Ebooks OPDS feed for use in ereading programs in scripting.']) ?>
|
||||||
|
<main>
|
||||||
|
<section class="narrow">
|
||||||
|
<? if($type == 'opds'){ ?>
|
||||||
|
<h1>The Standard Ebooks OPDS Feed</h1>
|
||||||
|
<p><a href="https://en.wikipedia.org/wiki/Open_Publication_Distribution_System">OPDS feeds</a> are designed for use with ereading apps on your phone or tablet, or with ereading systems like <a href="http://koreader.rocks/">KOreader</a>. Add our OPDS feed to your ereading app to search, browse, and download from our entire catalog, directly in your ereader.</p>
|
||||||
|
<p>They’re also perfect for scripting, or for libraries or other organizations who wish to download and process our catalog of ebooks.</p>
|
||||||
|
<? }elseif($type == 'rss'){ ?>
|
||||||
|
<h1>Standard Ebooks RSS Feeds</h1>
|
||||||
|
<p>RSS feeds are an alternative to <a href="/feeds/atom">Atom feeds</a>. They contain less information than Atom feeds, but might be better supported by some RSS readers.</p>
|
||||||
|
<? }elseif($type == 'atom'){ ?>
|
||||||
|
<h1>Standard Ebooks Atom Feeds</h1>
|
||||||
|
<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 RSS feeds. 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>
|
||||||
|
<? }else{ ?>
|
||||||
|
<h1>Standard Ebooks Ebook Feeds</h1>
|
||||||
|
<? } ?>
|
||||||
|
<?= Template::FeedHowTo() ?>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
<?= Template::Footer() ?>
|
|
@ -1,35 +1,39 @@
|
||||||
<?
|
<?
|
||||||
require_once('Core.php');
|
require_once('Core.php');
|
||||||
|
|
||||||
?><?= Template::Header(['title' => 'Atom Ebook Feeds', 'description' => 'A list of available Atom 1.0 feeds of Standard Ebooks ebooks.']) ?>
|
?><?= Template::Header(['title' => 'Atom 1.0 Ebook Feeds', 'description' => 'A list of available Atom 1.0 feeds of Standard Ebooks ebooks.']) ?>
|
||||||
<main>
|
<main>
|
||||||
<article>
|
<section class="narrow">
|
||||||
<h1>Atom 1.0 Feeds</h1>
|
<h1>Atom 1.0 Ebook Feeds</h1>
|
||||||
<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 RSS feeds. Most RSS clients can read both Atom and RSS feeds.</p>
|
<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>
|
<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>
|
||||||
<ul class="feed">
|
<?= Template::FeedHowTo() ?>
|
||||||
<li>
|
<section id="atom-feeds">
|
||||||
<p><a href="/feeds/atom/new-releases">New releases</a></p>
|
<h2>Atom Feeds</h2>
|
||||||
<p class="url"><?= SITE_URL ?>/feeds/atom/new-releases</p>
|
|
||||||
<p>The thirty latest Standard Ebooks, most-recently-released first.</p>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<p><a href="/feeds/atom/all">All ebooks</a></p>
|
|
||||||
<p class="url"><?= SITE_URL ?>/feeds/atom/all</p>
|
|
||||||
<p>All Standard Ebooks, most-recently-released first.</p>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<section id="atom-ebooks-by-subject">
|
|
||||||
<h2>Ebooks by subject</h2>
|
|
||||||
<ul class="feed">
|
<ul class="feed">
|
||||||
<? foreach(SE_SUBJECTS as $subject){ ?>
|
|
||||||
<li>
|
<li>
|
||||||
<p><a href="/feeds/atom/subjects/<?= Formatter::MakeUrlSafe($subject) ?>"><?= Formatter::ToPlainText($subject) ?></a></p>
|
<p><a href="/feeds/atom/new-releases">New releases</a> (Public)</p>
|
||||||
<p class="url"><?= SITE_URL ?>/feeds/atom/subjects/<?= Formatter::MakeUrlSafe($subject) ?></p>
|
<p class="url"><?= SITE_URL ?>/feeds/atom/new-releases</p>
|
||||||
|
<p>The fifteen latest Standard Ebooks, most-recently-released first.</p>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<p><a href="/feeds/atom/all">All ebooks</a></p>
|
||||||
|
<p class="url"><?= SITE_URL ?>/feeds/atom/all</p>
|
||||||
|
<p>All Standard Ebooks, most-recently-released first.</p>
|
||||||
</li>
|
</li>
|
||||||
<? } ?>
|
|
||||||
</ul>
|
</ul>
|
||||||
|
<section id="atom-ebooks-by-subject">
|
||||||
|
<h2>Ebooks by subject</h2>
|
||||||
|
<ul class="feed">
|
||||||
|
<? foreach(SE_SUBJECTS as $subject){ ?>
|
||||||
|
<li>
|
||||||
|
<p><a href="/feeds/atom/subjects/<?= Formatter::MakeUrlSafe($subject) ?>"><?= Formatter::ToPlainText($subject) ?></a></p>
|
||||||
|
<p class="url"><?= SITE_URL ?>/feeds/atom/subjects/<?= Formatter::MakeUrlSafe($subject) ?></p>
|
||||||
|
</li>
|
||||||
|
<? } ?>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
</section>
|
</section>
|
||||||
</article>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
<?= Template::Footer() ?>
|
<?= Template::Footer() ?>
|
||||||
|
|
|
@ -1,18 +1,22 @@
|
||||||
<?
|
<?
|
||||||
require_once('Core.php');
|
require_once('Core.php');
|
||||||
|
|
||||||
?><?= Template::Header(['title' => 'Atom Ebook Feeds by Subject', 'description' => 'A list of available Atom 1.0 feeds of Standard Ebooks ebooks by subject.']) ?>
|
?><?= Template::Header(['title' => 'Atom 1.0 Ebook Feeds by Subject', 'description' => 'A list of available Atom 1.0 feeds of Standard Ebooks ebooks by subject.']) ?>
|
||||||
<main>
|
<main>
|
||||||
<article>
|
<article>
|
||||||
<h1>Atom 1.0 Feeds by Subject</h1>
|
<h1>Atom 1.0 Ebook Feeds by Subject</h1>
|
||||||
<ul class="feed">
|
<?= Template::FeedHowTo() ?>
|
||||||
<? foreach(SE_SUBJECTS as $subject){ ?>
|
<section id="atom-feeds">
|
||||||
<li>
|
<h2>Atom Feeds</h2>
|
||||||
<p><a href="/feeds/atom/subjects/<?= Formatter::MakeUrlSafe($subject) ?>"><?= Formatter::ToPlainText($subject) ?></a></p>
|
<ul class="feed">
|
||||||
<p class="url"><?= SITE_URL ?>/feeds/atom/subjects/<?= Formatter::MakeUrlSafe($subject) ?></p>
|
<? foreach(SE_SUBJECTS as $subject){ ?>
|
||||||
</li>
|
<li>
|
||||||
<? } ?>
|
<p><a href="/feeds/atom/subjects/<?= Formatter::MakeUrlSafe($subject) ?>"><?= Formatter::ToPlainText($subject) ?></a></p>
|
||||||
</ul>
|
<p class="url"><?= SITE_URL ?>/feeds/atom/subjects/<?= Formatter::MakeUrlSafe($subject) ?></p>
|
||||||
|
</li>
|
||||||
|
<? } ?>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
</article>
|
</article>
|
||||||
</main>
|
</main>
|
||||||
<?= Template::Footer() ?>
|
<?= Template::Footer() ?>
|
||||||
|
|
|
@ -10,28 +10,30 @@ require_once('Core.php');
|
||||||
|
|
||||||
?><?= Template::Header(['title' => 'Ebook Feeds', 'description' => 'A list of available feeds of Standard Ebooks ebooks.']) ?>
|
?><?= Template::Header(['title' => 'Ebook Feeds', 'description' => 'A list of available feeds of Standard Ebooks ebooks.']) ?>
|
||||||
<main>
|
<main>
|
||||||
<article>
|
<section class="narrow">
|
||||||
<h1>Ebook Feeds</h1>
|
<h1>Ebook Feeds</h1>
|
||||||
<p>We offers several feeds that you can use to get notified about new ebooks, or to browse and download from our catalog directly in your ereader.</p>
|
<p>We offer several ebook feeds that you can use in your ereading app to browse, search, and download from our catalog. You can also add our feeds to your RSS client to get notified of new ebooks as they’re released.</p>
|
||||||
|
<?= Template::FeedHowTo() ?>
|
||||||
<section id="opds-feeds">
|
<section id="opds-feeds">
|
||||||
<h2>OPDS 1.2 feeds</h2>
|
<h2>OPDS 1.2 feeds</h2>
|
||||||
<p><a href="https://en.wikipedia.org/wiki/Open_Publication_Distribution_System">OPDS feeds</a> are designed for use with ereading systems like <a href="http://koreader.rocks/">KOreader</a> or <a href="https://calibre-ebook.com">Calibre</a>, or with ereaders like <a href="https://johnfactotum.github.io/foliate/">Foliate</a>. They allow you to search, browse, and download from our catalog, directly in your ereader. They’re also perfect for organizations who wish to download and process our catalog efficiently.</p>
|
<p><a href="https://en.wikipedia.org/wiki/Open_Publication_Distribution_System">OPDS feeds</a> are designed for use with ereading apps on your phone or tablet, or with ereading systems like <a href="http://koreader.rocks/">KOreader</a>. Add our OPDS feed to your ereading app to search, browse, and download from our entire catalog, directly in your ereader.</p>
|
||||||
|
<p>They’re also perfect for scripting, or for libraries or other organizations who wish to download and process our catalog of ebooks.</p>
|
||||||
<ul class="feed">
|
<ul class="feed">
|
||||||
<li>
|
<li>
|
||||||
<p><a href="/feeds/opds">The Standard Ebooks OPDS feed</a></p>
|
<p><a href="/feeds/opds">The Standard Ebooks OPDS feed</a></p>
|
||||||
<p class="url"><?= SITE_URL ?>/feeds/opds</p>
|
<p class="url"><?= SITE_URL ?>/feeds/opds</p>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<section>
|
<section id="opds-how-tos-and-resources">
|
||||||
<h3>OPDS how-tos and resources</h3>
|
<h3>OPDS how-tos and resources</h3>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<p><a href="https://github.com/koreader/koreader/wiki/OPDS-support">Using OPDS with KOreader</a></p>
|
<p><a href="https://github.com/koreader/koreader/wiki/OPDS-support">Using OPDS with KOreader</a></p>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<p><a href="https://github.com/steinarb/opds-reader">OPDS Reader</a>, a plugin that adds OPDS support to Calibre</p>
|
<p><a href="https://github.com/steinarb/opds-reader">OPDS Reader</a>, a plugin that adds OPDS support to Calibre</p>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
<section id="atom-feeds">
|
<section id="atom-feeds">
|
||||||
|
@ -40,9 +42,9 @@ 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>
|
<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>
|
||||||
<ul class="feed">
|
<ul class="feed">
|
||||||
<li>
|
<li>
|
||||||
<p><a href="/feeds/atom/new-releases">New releases</a></p>
|
<p><a href="/feeds/atom/new-releases">New releases</a> (Public)</p>
|
||||||
<p class="url"><?= SITE_URL ?>/feeds/atom/new-releases</p>
|
<p class="url"><?= SITE_URL ?>/feeds/atom/new-releases</p>
|
||||||
<p>The thirty latest Standard Ebooks, most-recently-released first.</p>
|
<p>The fifteen latest Standard Ebooks, most-recently-released first.</p>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<p><a href="/feeds/atom/all">All ebooks</a></p>
|
<p><a href="/feeds/atom/all">All ebooks</a></p>
|
||||||
|
@ -67,9 +69,9 @@ require_once('Core.php');
|
||||||
<p>RSS feeds are an alternative to Atom feeds. They contain less information than Atom feeds, but might be better supported by some RSS readers.</p>
|
<p>RSS feeds are an alternative to Atom feeds. They contain less information than Atom feeds, but might be better supported by some RSS readers.</p>
|
||||||
<ul class="feed">
|
<ul class="feed">
|
||||||
<li>
|
<li>
|
||||||
<p><a href="/feeds/rss/new-releases">New releases</a></p>
|
<p><a href="/feeds/rss/new-releases">New releases</a> (Public)</p>
|
||||||
<p class="url"><?= SITE_URL ?>/feeds/rss/new-releases</p>
|
<p class="url"><?= SITE_URL ?>/feeds/rss/new-releases</p>
|
||||||
<p>The thirty latest Standard Ebooks, most-recently-released first.</p>
|
<p>The fifteen latest Standard Ebooks, most-recently-released first.</p>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<p><a href="/feeds/rss/all">All ebooks</a></p>
|
<p><a href="/feeds/rss/all">All ebooks</a></p>
|
||||||
|
@ -89,6 +91,6 @@ require_once('Core.php');
|
||||||
</ul>
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
</article>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
<?= Template::Footer() ?>
|
<?= Template::Footer() ?>
|
||||||
|
|
|
@ -13,18 +13,17 @@ try{
|
||||||
}
|
}
|
||||||
catch(\Exception $ex){
|
catch(\Exception $ex){
|
||||||
http_response_code(500);
|
http_response_code(500);
|
||||||
include(WEB_ROOT . '/404.php');
|
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
print("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<?xml-stylesheet href=\"/feeds/opds/style\" type=\"text/xsl\"?>\n");
|
print("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<?xml-stylesheet href=\"/feeds/opds/style\" type=\"text/xsl\"?>\n");
|
||||||
?>
|
?>
|
||||||
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:schema="http://schema.org/" xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/">
|
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:schema="http://schema.org/" xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/">
|
||||||
<id><?= SITE_URL ?>/feeds/opds/all?query=<?= urlencode($query) ?></id>
|
<id><?= SITE_URL ?>/feeds/opds/all?query=<?= urlencode($query) ?></id>
|
||||||
<link href="<?= SITE_URL ?>/feeds/opds/all?query=<?= urlencode($query) ?>" rel="self" type="application/atom+xml;profile=opds-catalog"/>
|
<link href="<?= SITE_URL ?>/feeds/opds/all?query=<?= urlencode($query) ?>" rel="self" type="application/atom+xml;profile=opds-catalog; charset=utf-8"/>
|
||||||
<link href="<?= SITE_URL ?>/ebooks/ebooks?query=<?= urlencode($query) ?>" rel="alternate" type="text/html"/>
|
<link href="<?= SITE_URL ?>/ebooks/ebooks?query=<?= urlencode($query) ?>" rel="alternate" type="text/html"/>
|
||||||
<link href="<?= SITE_URL ?>/feeds/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; charset=utf-8"/>
|
||||||
<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 ?>/feeds/opds/all" rel="http://opds-spec.org/crawlable" type="application/atom+xml;profile=opds-catalog;kind=acquisition; charset=utf-8"/>
|
||||||
<link href="<?= SITE_URL ?>/ebooks/opensearch" rel="search" type="application/opensearchdescription+xml"/>
|
<link href="<?= SITE_URL ?>/ebooks/opensearch" rel="search" type="application/opensearchdescription+xml; charset=utf-8"/>
|
||||||
<title>Search Results</title>
|
<title>Search Results</title>
|
||||||
<subtitle>Results for “<?= Formatter::ToPlainXmlText($query) ?>”.</subtitle>
|
<subtitle>Results for “<?= Formatter::ToPlainXmlText($query) ?>”.</subtitle>
|
||||||
<icon><?= SITE_URL ?>/images/logo.png</icon>
|
<icon><?= SITE_URL ?>/images/logo.png</icon>
|
||||||
|
|
|
@ -1,34 +1,38 @@
|
||||||
<?
|
<?
|
||||||
require_once('Core.php');
|
require_once('Core.php');
|
||||||
|
|
||||||
?><?= Template::Header(['title' => 'RSS Ebook Feeds', 'description' => 'A list of available RSS 2.0 feeds of Standard Ebooks ebooks.']) ?>
|
?><?= Template::Header(['title' => 'RSS 2.0 Ebook Feeds', 'description' => 'A list of available RSS 2.0 feeds of Standard Ebooks ebooks.']) ?>
|
||||||
<main>
|
<main>
|
||||||
<article>
|
<section class="narrow">
|
||||||
<h1>RSS 2.0 feeds</h1>
|
<h1>RSS 2.0 Ebook Feeds</h1>
|
||||||
<p>RSS feeds are an alternative to Atom feeds. They contain less information than Atom feeds, but might be better supported by some RSS readers.</p>
|
<p>RSS feeds are an alternative to Atom feeds. They contain less information than Atom feeds, but might be better supported by some RSS readers.</p>
|
||||||
<ul class="feed">
|
<?= Template::FeedHowTo() ?>
|
||||||
<li>
|
<section id="rss-feeds">
|
||||||
<p><a href="/feeds/rss/new-releases">New releases</a></p>
|
<h2>RSS Feeds</h2>
|
||||||
<p class="url"><?= SITE_URL ?>/feeds/rss/new-releases</p>
|
|
||||||
<p>The thirty latest Standard Ebooks, most-recently-released first.</p>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<p><a href="/feeds/rss/all">All ebooks</a></p>
|
|
||||||
<p class="url"><?= SITE_URL ?>/feeds/rss/all</p>
|
|
||||||
<p>All Standard Ebooks, most-recently-released first.</p>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<section id="rss-ebooks-by-subject">
|
|
||||||
<h3>Ebooks by subject</h3>
|
|
||||||
<ul class="feed">
|
<ul class="feed">
|
||||||
<? foreach(SE_SUBJECTS as $subject){ ?>
|
|
||||||
<li>
|
<li>
|
||||||
<p><a href="/feeds/rss/subjects/<?= Formatter::MakeUrlSafe($subject) ?>"><?= Formatter::ToPlainText($subject) ?></a></p>
|
<p><a href="/feeds/rss/new-releases">New releases</a> (Public)</p>
|
||||||
<p class="url"><?= SITE_URL ?>/feeds/rss/subjects/<?= Formatter::MakeUrlSafe($subject) ?></p>
|
<p class="url"><?= SITE_URL ?>/feeds/rss/new-releases</p>
|
||||||
|
<p>The fifteen latest Standard Ebooks, most-recently-released first.</p>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<p><a href="/feeds/rss/all">All ebooks</a></p>
|
||||||
|
<p class="url"><?= SITE_URL ?>/feeds/rss/all</p>
|
||||||
|
<p>All Standard Ebooks, most-recently-released first.</p>
|
||||||
</li>
|
</li>
|
||||||
<? } ?>
|
|
||||||
</ul>
|
</ul>
|
||||||
|
<section id="rss-ebooks-by-subject">
|
||||||
|
<h3>Ebooks by subject</h3>
|
||||||
|
<ul class="feed">
|
||||||
|
<? foreach(SE_SUBJECTS as $subject){ ?>
|
||||||
|
<li>
|
||||||
|
<p><a href="/feeds/rss/subjects/<?= Formatter::MakeUrlSafe($subject) ?>"><?= Formatter::ToPlainText($subject) ?></a></p>
|
||||||
|
<p class="url"><?= SITE_URL ?>/feeds/rss/subjects/<?= Formatter::MakeUrlSafe($subject) ?></p>
|
||||||
|
</li>
|
||||||
|
<? } ?>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
</section>
|
</section>
|
||||||
</article>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
<?= Template::Footer() ?>
|
<?= Template::Footer() ?>
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
<?
|
<?
|
||||||
require_once('Core.php');
|
require_once('Core.php');
|
||||||
|
|
||||||
?><?= Template::Header(['title' => 'RSS Ebook Feeds by Subject', 'description' => 'A list of available RSS 2.0 feeds of Standard Ebooks ebooks by subject.']) ?>
|
?><?= Template::Header(['title' => 'RSS 2.0 Ebook Feeds by Subject', 'description' => 'A list of available RSS 2.0 feeds of Standard Ebooks ebooks by subject.']) ?>
|
||||||
<main>
|
<main>
|
||||||
<article>
|
<article>
|
||||||
<h1>RSS 2.0 Feeds by Subject</h1>
|
<h1>RSS 2.0 Ebook Feeds by Subject</h1>
|
||||||
<ul class="feed">
|
<ul class="feed">
|
||||||
<? foreach(SE_SUBJECTS as $subject){ ?>
|
<? foreach(SE_SUBJECTS as $subject){ ?>
|
||||||
<li>
|
<li>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue