Merge pull request #57 from gutenbergtools/gutenberg1

Gutenberg1
gutenberg1
Eric Hellman 2020-09-04 13:44:38 -04:00 committed by GitHub
commit c4c329b600
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 497 additions and 1105 deletions

File diff suppressed because it is too large Load Diff

View File

@ -80,7 +80,7 @@ class BibrecPage (Page.Page):
))
if os.format in ('html', 'mobile'):
if os.format == 'html':
cat = BaseSearcher.Cat ()
cat.header = _('Similar Books')
cat.title = _('Readers also downloaded…')
@ -101,30 +101,9 @@ class BibrecPage (Page.Page):
cat.order = 33
os.entries.append (cat)
if os.format in ('mobile', ):
for author in dc.authors:
cat = BaseSearcher.Cat ()
cat.title = _('By {author}').format (author = author.name_and_dates)
cat.rel = 'related'
cat.url = os.url ('author', id = author.id)
cat.class_ += 'navlink grayed'
cat.icon = 'author'
cat.order = 31
os.entries.append (cat)
for subject in dc.subjects:
cat = BaseSearcher.Cat ()
cat.title = _('On {subject}').format (subject = subject.subject)
cat.rel = 'related'
cat.url = os.url ('subject', id = subject.id)
cat.class_ += 'navlink grayed'
cat.icon = 'subject'
cat.order = 32
os.entries.append (cat)
os.total_results = 1
os.template = 'results' if os.format == 'mobile' else 'bibrec'
os.template = 'bibrec'
os.page = 'bibrec'
os.og_type = 'book'
os.finalize ()

View File

@ -19,7 +19,6 @@ pgdatabase: 'gutenberg'
pguser: 'postgres'
host: 'www.gutenberg.org'
host_mobile: 'm.gutenberg.org'
host_https: 1
file_host: 'www.gutenberg.org'

View File

@ -87,7 +87,6 @@ def main():
'daemonize': False,
'pidfile': None,
'host': 'localhost',
'host_mobile': 'localhost',
'file_host': 'localhost',
})
@ -165,7 +164,7 @@ def main():
cherrypy.config['js_mtime'] = t
cherrypy.config['all_hosts'] = (
cherrypy.config['host'], cherrypy.config['host_mobile'], cherrypy.config['file_host'])
cherrypy.config['host'], cherrypy.config['file_host'])
cherrypy.config.update({'error_page.404': error_page_404})

View File

@ -13,19 +13,21 @@ Serve cover images of most popular and latest ebooks.
"""
from __future__ import unicode_literals
import re
import cherrypy
import six
import textwrap
from libgutenberg import GutenbergGlobals as gg
import BaseSearcher
class CoverPages (object):
class CoverPages(object):
""" Output a gallery of cover pages. """
orders = { 'latest': 'release_date',
'popular': 'downloads' }
orders = {'latest': 'release_date',
'popular': 'downloads'}
@staticmethod
def serve (rows, size):
@ -33,72 +35,65 @@ class CoverPages (object):
cherrypy.response.headers['Content-Type'] = 'text/html; charset=utf-8'
cherrypy.response.headers['Content-Language'] = 'en'
s = """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en" xml:base="http://www.gutenberg.org">
<head>
<title>Cover Flow</title>
<!--<style>
.cover-thumb {
display: inline-block;
background-position: center;
background-repeat: no-repeat;
}
.cover-thumb-small {
width: 76px;
height: 110px;
}
.cover-thumb-medium {
width: 210px;
height: 310px;
}
</style>-->
</head>
<body><div>"""
s = ''
for row in rows:
url = '/' + row.filename
href = '/ebooks/%d' % row.pk
title = gg.xmlspecialchars (row.title)
title = title.replace ('"', '&quot;')
if row.title:
title = gg.xmlspecialchars (row.title) # handles <,>,&
#Shortening long titles for latest covers
title = title.replace('"', '&quot;')
title = title.replace("'", '&apos;')
else:
title = '!! missing title !!'
short_title = title
title_len = len(title)
short_title = re.sub(r"\-+", " ", short_title)
short_title = short_title.splitlines()[0]
if(title_len > 80):
short_title = textwrap.wrap(short_title, 80)[0]
s += """
<a href="{href}" title="{title}" target="_top">
<div class="cover_image">
<div class="cover_img">
<img src="{url}" alt="{title}" title="{title}" draggable="false">
</div>
<div class="cover_title">
<h5>{short_title}</h5>
</div>
</div>
</a>
""".format(url=url, href=href, title=title, short_title=short_title, size=size)
s += """<a href="{href}"
title="{title}"
class="cover-thumb cover-thumb-{size}" target="_top"
style="background-image: url({url})"> </a>\n""".format (
url = url, href = href, title = title, size = size)
return s.encode('utf-8')
return (s + '</div></body></html>\n').encode ('utf-8')
def index (self, count, size, order, **kwargs):
def index(self, count, size, order, **kwargs):
""" Internal help function. """
try:
count = int (count)
count = int(count)
if count < 1:
raise ValueError ('count < 0')
raise ValueError('count < 0')
if size not in ('small', 'medium'):
raise ValueError ('bogus size')
raise ValueError('bogus size')
order = 'books.%s' % self.orders[order]
rows = BaseSearcher.SQLSearcher.execute (
rows = BaseSearcher.SQLSearcher.execute(
"""SELECT files.filename, books.pk, books.title FROM files, books
WHERE files.fk_books = books.pk
AND files.diskstatus = 0
AND files.fk_filetypes = %%(size)s
ORDER BY %s DESC
OFFSET 1 LIMIT %%(count)s -- %s""" % (order, cherrypy.request.remote.ip),
{ 'count': count,
'size': 'cover.%s' % size,
})
{'count': count, 'size': 'cover.%s' % size,}
)
if rows:
return self.serve (rows, size)
return self.serve(rows, size)
except (ValueError, KeyError) as what:
raise cherrypy.HTTPError (400, 'Bad Request. %s' % six.text_type (what))
raise cherrypy.HTTPError (400, 'Bad Request. %s' % six.text_type(what))
except IOError:
pass
raise cherrypy.HTTPError (500, 'Internal Server Error.')

View File

@ -37,7 +37,6 @@ def format (format_, page, os_):
formatters = {}
formatters['opds'] = OPDSFormatter.OPDSFormatter ()
formatters['stanza'] = formatters['opds']
formatters['mobile'] = HTMLFormatter.MobileFormatter ()
formatters['html'] = HTMLFormatter.HTMLFormatter ()
formatters['json'] = JSONFormatter.JSONFormatter ()
# FIXME: only needed to load sitemap.xml templates

View File

@ -31,9 +31,6 @@ from i18n_tool import ugettext as _
# filetypes ignored on desktop site
NO_DESKTOP_FILETYPES = 'plucker qioo rdf rst rst.gen rst.master tei cover.medium cover.small'.split ()
# filetypes shown on mobile site
MOBILE_TYPES = (mt.epub, mt.mobi, mt.pdf, 'text/html', mt.html)
# filetypes which are usually handed over to a separate app on mobile devices
HANDOVER_TYPES = (mt.epub, mt.mobi, mt.pdf)
@ -187,44 +184,3 @@ class HTMLFormatter (XMLishFormatter):
if showncount == 0:
for file_ in dc.files + dc.generated_files:
file_.hidden = False
class MobileFormatter (XMLishFormatter):
""" Produce HTML output suitable for mobile devices. """
CONTENT_TYPE = mt.xhtml + '; charset=UTF-8'
DOCTYPE = 'html5'
def __init__ (self):
super (MobileFormatter, self).__init__ ()
def get_serializer (self):
return genshi.output.HTMLSerializer (doctype = self.DOCTYPE, strip_whitespace = False)
def fix_dc (self, dc, os):
""" Add some info to dc for easier templating.
Also make sure that dc `walks like a cat´. """
super (MobileFormatter, self).fix_dc (dc, os)
for file_ in dc.files + dc.generated_files:
if len (file_.mediatypes) == 1:
type_ = six.text_type (file_.mediatypes[0])
m = type_.partition (';')[0]
if m in MOBILE_TYPES:
cat = BaseSearcher.Cat ()
cat.type = file_.mediatypes[0]
cat.header = _('Download')
cat.title = file_.hr_filetype
cat.extra = file_.hr_extent
cat.charset = file_.encoding
cat.url = '/' + file_.filename
cat.icon = dc.icon
cat.icon2 = 'download'
cat.class_ += 'filelink'
cat.order = 20
os.entries.append (cat)

View File

@ -35,12 +35,7 @@ class BookSearchPage (SearchPage):
os.f_format_icon = os.format_icon_titles
if os.sort_order == 'random':
sql.where.append ("""
pk in (select floor (random () * maxbook)::integer
from generate_series (1, 30), (select max (pk) as maxbook
from books) xbks1)
""")
sql.where.append ("pk in (select pk from books order by random() limit 20)")
if len (os.query):
sql.fulltext ('books.tsvec', os.query)
os.title = _("Books: {title}").format (title = os.query)
@ -270,7 +265,7 @@ class AuthorPage (SearchPage):
os.entries.insert (0, cat)
# author aliases
if os.format in ('html', 'mobile'):
if os.format == 'html':
rows = BaseSearcher.SQLSearcher.execute (
"""SELECT alias AS title FROM aliases
WHERE fk_authors = %(fk_authors)s AND alias_heading = 1""",

View File

@ -30,7 +30,6 @@ class Start (Page.Page):
os.search_terms = ''
os.title = {
'mobile': _('PG Mobile'),
'opds': _('Project Gutenberg'),
'stanza': _('Project Gutenberg')
}.get (os.format, _('Search Project Gutenberg'))

View File

@ -86,17 +86,27 @@ sudo systemctl status autocat3.service
# we are having problems with monit trying to restart. It might be necessary to also stop
# monit. Further diagnosis is forthcoming.
## Development
create a "feature" branch on on the git repo, using either master or development as base.
when your code is working, submit a pull request to master or development as appropriate.
## updates
# currently gutenberg1 is production deployment, gutenberg2 is dev deployment
# to do a new deployment, first pull from the master or dev as appropriate
# into gutenberg1 or gutenberg2.
# DONT edit files on the deployment servers, they should always be updated from the git remote.
su - autocat
# or sudo su - autocat if you can sudo
cd autocat3
git pull
git checkout remotes/origin/master
git fetch origin
#for gutenberg1
git checkout remotes/origin/gutenberg1
# for gutenberg2
# git checkout remotes/origin/gutenberg2
git checkout remotes/origin/gutenberg2
pipenv install --ignore-pipfile

View File

@ -1,14 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
DON'T USE THIS PAGE FOR SCRAPING.
Seriously. You'll only get your IP blocked.
Read http://www.gutenberg.org/feeds/ to learn how to download Project
Gutenberg metadata much faster than by scraping.
-->
<html xmlns="http://www.w3.org/1999/xhtml"
@ -55,7 +51,7 @@ Gutenberg metadata much faster than by scraping.
<head xmlns:og="http://opengraphprotocol.org/schema/">
${site_head ()}
${site_head()}
<title>${os.title} - Free Ebook</title>
@ -69,9 +65,10 @@ Gutenberg metadata much faster than by scraping.
</head>
<body>
<div id="mw-head-dummy" class="noprint" />
<div class="container">
${site_top()}
<div id="content" itemscope="itemscope" itemtype="http://schema.org/Book" i18n:comment="On the 'bibrec' page.">
<div class="page_content" id="content" itemscope="itemscope" itemtype="http://schema.org/Book" i18n:comment="On the 'bibrec' page.">
<div class="breadcrumbs noprint">
<ul>
@ -84,12 +81,10 @@ Gutenberg metadata much faster than by scraping.
</py:for>
</ul>
</div>
<div class="header">
<h1 itemprop="name">${os.title}</h1>
</div>
<div class="body">
<div class="page-body">
<div property="dcterms:publisher" itemprop="publisher" content="Project Gutenberg" />
<div itemprop="bookFormat" content="EBook" />
@ -110,34 +105,134 @@ Gutenberg metadata much faster than by scraping.
<div id="social" class="noprint">
<ul>
<!--! Broken. Dialog opens and closes immediately. Disabled for now.
<li>
${fb_share (os.canonical_url, os.title.encode ('utf-8'),
os.description.encode ('utf-8'), os.cover_thumb_url)}
</li>
-->
<li>
${tw_share (os.canonical_url, os.twit)}
${tw_share(os.canonical_url, os.twit)}
</li>
<li>
<a onclick="printpage ()" title="Print this page"><span class="icon icon_print" /></a>
${fb_share(os.canonical_url)}
</li>
<li>
<a onclick="printpage()" title="Print this page"><span class="icon icon_print" /></a>
</li>
</ul>
</div>
<div id="qr">
<!--! qr code of mobile page for screen -->
<span class="qrcode qrcode-desktop" title="Scan QR Code for this page." />
</div>
</div>
<div id="tabs-wrapper">
<div id="tabs">
<ul class="noprint">
<li><a href="#download">Download</a></li>
<li><a href="#bibrec">Bibrec</a></li>
</ul>
<div id="download" i18n:comment="On the 'Download' tab of the 'bibrec' page.">
<py:for each="e in os.entries">
<py:if test="isinstance(e, bs.DC)">
<div about="[ebook:$e.project_gutenberg_id]" rel="dcterms:hasFormat" >
<h2>Download This eBook</h2>
<table class="files">
<colgroup>
<col class="narrow" />
<col />
<col />
<col />
<col class="narrow noprint" />
<col class="narrow noprint" />
<col class="narrow noprint" />
</colgroup>
<tr>
<th />
<th>Format <span>${help ('Format')}</span></th>
<th class="noscreen">Url</th>
<th i18n:comment="Size of a file." class="right">Size</th>
<th class="noprint"><span>${help ('Dropbox')}</span></th>
<th class="noprint"><span>${help ('Google Drive')}</span></th>
<th class="noprint"><span>${help ('OneDrive')}</span></th>
</tr>
<tr py:for="i, file_ in enumerate(e.files)"
py:if="not file_.hidden"
class="${i%2 and 'odd' or 'even'}"
about="${file_.url}" typeof="pgterms:file">
<td><span class="icon icon_${e.icon}" /></td>
<td property="dcterms:format" content="${file_.mediatypes[-1]}" datatype="dcterms:IMT"
class="unpadded icon_save"
><a href="/${file_.filename}" type="${file_.mediatypes[-1]}" class="link"
title="Download">${file_.hr_filetype}</a></td>
<td class="noscreen">${file_.url}</td>
<td class="right"
property="dcterms:extent" content="${file_.extent}">${file_.hr_extent}</td>
<td class="noprint">
<a py:if="file_.dropbox_url"
href="${file_.dropbox_url}"
title="Send to Dropbox." rel="nofollow"><span class="icon icon_dropbox" /></a>
</td>
<td class="noprint">
<a py:if="file_.gdrive_url"
href="${file_.gdrive_url}"
title="Send to Google Drive." rel="nofollow"><span class="icon icon_gdrive" /></a>
</td>
<td class="noprint">
<a py:if="file_.honeypot_url"
href="${file_.honeypot_url}"
title="Send to MegaUpload." rel="nofollow" />
<a py:if="file_.msdrive_url"
href="${file_.msdrive_url}"
title="Send to OneDrive." rel="nofollow"><span class="icon icon_msdrive" /></a>
</td>
</tr>
<!--! more files ... -->
<tr py:if="e.base_dir"
class="${i%2 and 'odd' or 'even'}">
<td><span class="icon icon_folder" /></td>
<td class="unpadded icon_file"><a href="${e.base_dir}" class="link"
i18n:comment="Link to the directory containing all files.">More Files…</a></td>
<td class="noscreen">${os.qualify (e.base_dir)}</td>
<td/>
<td class="noprint"><!--! dropbox column --></td>
<td class="noprint"><!--! gdrive column --></td>
<td class="noprint"><!--! msdrive column --></td>
</tr>
</table>
</div>
</py:if>
</py:for>
</div> <!-- download -->
<div id="more_stuff">
<py:for each="n, e in enumerate (os.entries)">
<py:if test="isinstance (e, bs.Cat) and e.rel not in ('start', )">
<py:if test="e.header and old_header != e.header">
<h2 class="header">${e.header}</h2>
</py:if>
<?python old_header = e.header ?>
<div class="${e.class_}">
<a rel="nofollow"
href="${e.url}"
type="${e.type}"
charset="${e.charset}"
accesskey="${str (n % 10)}">
<span class="cell leftcell">
<span class="icon icon_${e.icon}" />
</span>
<span class="cell content">
<span class="title">${e.title}</span>
<span py:if="e.subtitle" class="subtitle">${e.subtitle}</span>
<span py:if="e.extra" class="extra">${e.extra}</span>
</span>
<span class="hstrut" />
</a>
</div>
</py:if>
</py:for>
</div> <!-- more stuff -->
<div id="bibrec" i18n:comment="On the 'bibrec' tab of the 'bibrec' page.">
<py:for each="e in os.entries">
<py:if test="isinstance (e, bs.DC)">
@ -170,23 +265,23 @@ Gutenberg metadata much faster than by scraping.
</td>
<td py:when="marc.code[0]=='5'">
<?python
text = gg.xmlspecialchars (marc.text)
text = re.sub (r'(//\S+)', r'<a href="\1">\1</a>', text)
text = re.sub (r'#(\d+)', r'<a href="/ebooks/\1">#\1</a>', text)
text = gg.xmlspecialchars(marc.text)
text = re.sub(r'(//\S+)', r'<a href="\1">\1</a>', text)
text = re.sub(r'#(\d+)', r'<a href="/ebooks/\1">#\1</a>', text)
?>
${ Markup (gg.insert_breaks (text)) }
</td>
<td py:when="marc.code=='245'" itemprop="headline">
${ Markup (gg.insert_breaks (gg.xmlspecialchars (marc.text))) }
${ Markup (gg.insert_breaks(gg.xmlspecialchars(marc.text))) }
</td>
<td py:when="marc.code=='240'" itemprop="alternativeHeadline">
${ Markup (gg.insert_breaks (gg.xmlspecialchars (marc.text))) }
${ Markup (gg.insert_breaks(gg.xmlspecialchars(marc.text))) }
</td>
<td py:when="marc.code=='246'" itemprop="alternativeHeadline">
${ Markup (gg.insert_breaks (gg.xmlspecialchars (marc.text))) }
${ Markup (gg.insert_breaks(gg.xmlspecialchars(marc.text))) }
</td>
<td py:otherwise="">
${ Markup (gg.insert_breaks (gg.xmlspecialchars (marc.text))) }
${ Markup (gg.insert_breaks(gg.xmlspecialchars(marc.text))) }
</td>
</py:choose>
</tr>
@ -200,7 +295,7 @@ Gutenberg metadata much faster than by scraping.
<tr py:for="locc in e.loccs"
property="dcterms:subject" datatype="dcterms:LCC" content="${locc.id}">
<th>LoC Class</th>
<th>LoC Class</th>
<td>
<a href="/browse/loccs/${locc.id.lower ()}">${locc.id}: ${locc.locc}</a>
</td>
@ -226,12 +321,12 @@ Gutenberg metadata much faster than by scraping.
</tr>
<tr property="dcterms:issued" datatype="xsd:date" content="${e.xsd_release_date_time}">
<th>Release Date</th>
<th>Release Date</th>
<td itemprop="datePublished">${e.hr_release_date}</td>
</tr>
<tr>
<th>Copyright Status</th>
<th>Copyright Status</th>
<td property="dcterms:rights">${e.rights}</td>
</tr>
@ -251,122 +346,13 @@ Gutenberg metadata much faster than by scraping.
</py:if>
</py:for>
<div id="more_stuff">
<py:for each="n, e in enumerate (os.entries)">
<py:if test="isinstance (e, bs.Cat) and e.rel not in ('start', )">
<py:if test="e.header and old_header != e.header">
<h2 class="header">${e.header}</h2>
</py:if>
<?python old_header = e.header ?>
<div class="${e.class_}">
<a rel="nofollow"
href="${e.url}"
type="${e.type}"
charset="${e.charset}"
accesskey="${str (n % 10)}">
<span class="cell leftcell">
<span class="icon icon_${e.icon}" />
</span>
<span class="cell content">
<span class="title">${e.title}</span>
<span py:if="e.subtitle" class="subtitle">${e.subtitle}</span>
<span py:if="e.extra" class="extra">${e.extra}</span>
</span>
<span class="hstrut" />
</a>
</div>
</py:if>
</py:for>
</div> <!-- more stuff -->
</div> <!--! bibrec -->
<div id="download" i18n:comment="On the 'Download' tab of the 'bibrec' page.">
<py:for each="e in os.entries">
<py:if test="isinstance (e, bs.DC)">
<div about="[ebook:$e.project_gutenberg_id]" rel="dcterms:hasFormat" ><!--! rev="dcterms:isFormatOf" -->
<h2>Download This eBook</h2>
<table class="files">
<colgroup>
<col class="narrow" />
<col />
<col />
<col />
<col class="narrow noprint" />
<col class="narrow noprint" />
<col class="narrow noprint" />
</colgroup>
<tr>
<th />
<th>Format <span>${help ('Format')}</span></th>
<th class="noscreen">Url</th>
<th i18n:comment="Size of a file." class="right">Size</th>
<th class="noprint"><span>${help ('Dropbox')}</span></th>
<th class="noprint"><span>${help ('Google Drive')}</span></th>
<th class="noprint"><span>${help ('OneDrive')}</span></th>
</tr>
<tr py:for="i, file_ in enumerate (e.files)"
py:if="not file_.hidden"
class="${i%2 and 'odd' or 'even'}"
about="${file_.url}" typeof="pgterms:file">
<td><span class="icon icon_${e.icon}" /></td>
<td property="dcterms:format" content="${file_.mediatypes[-1]}" datatype="dcterms:IMT"
class="unpadded icon_save"
><a href="/${file_.filename}" type="${file_.mediatypes[-1]}" class="link"
title="Download">${file_.hr_filetype}</a></td>
<td class="noscreen">${file_.url}</td>
<td class="right"
property="dcterms:extent" content="${file_.extent}">${file_.hr_extent}</td>
<td class="noprint">
<a py:if="file_.dropbox_url"
href="${file_.dropbox_url}"
title="Send to Dropbox." rel="nofollow"><span class="icon icon_dropbox" /></a>
</td>
<td class="noprint">
<a py:if="file_.gdrive_url"
href="${file_.gdrive_url}"
title="Send to Google Drive." rel="nofollow"><span class="icon icon_gdrive" /></a>
</td>
<td class="noprint">
<a py:if="file_.honeypot_url"
href="${file_.honeypot_url}"
title="Send to MegaUpload." rel="nofollow" />
<a py:if="file_.msdrive_url"
href="${file_.msdrive_url}"
title="Send to OneDrive." rel="nofollow"><span class="icon icon_msdrive" /></a>
</td>
</tr>
<!--! more files ... -->
<tr py:if="e.base_dir"
class="${i%2 and 'odd' or 'even'}">
<td><span class="icon icon_folder" /></td>
<td class="unpadded icon_file"><a href="${e.base_dir}" class="link"
i18n:comment="Link to the directory containing all files.">More Files…</a></td>
<td class="noscreen">${os.qualify (e.base_dir)}</td>
<td/>
<td class="noprint"><!--! dropbox column --></td>
<td class="noprint"><!--! gdrive column --></td>
<td class="noprint"><!--! msdrive column --></td>
</tr>
</table>
</div>
</py:if>
</py:for>
</div> <!-- download -->
</div> <!--! tabs -->
</div> <!--! tabs-wrapper -->
</div> <!--! body -->
</div>
<div id="dialog" class="hidden">
</div>
@ -380,7 +366,6 @@ Gutenberg metadata much faster than by scraping.
about=""
rel="dcterms:conformsTo"
resource="http://www.w3.org/TR/rdfa-syntax" /></a>
<a href="${os.url_carry ('bibrec', format='rdf')}"
title="Download RDF/XML Metadata for this ebook."><img
src="http://www.w3.org/RDF/icons/rdf_metadata_button.32"
@ -389,11 +374,9 @@ Gutenberg metadata much faster than by scraping.
alt="RDF/XML Metadata" /></a>
-->
${site_footer ()}
${site_footer()}
</div>
${site_top ()}
</body>
</html>

View File

@ -7,16 +7,24 @@
xmlns:og="http://opengraphprotocol.org/schema/"
xmlns:fb="http://www.facebook.com/2008/fbml"
py:strip="">
<xi:include href="site-layout.html" />
<xi:include href="social-functions.html" />
<head>
<style>
.icon { background: transparent url(/pics/sprite.png?${cherrypy.config['css_mtime']}) 0 0 no-repeat; }
</style>
<link rel="stylesheet" type="text/css"
href="/css/pg-desktop-one.css?${cherrypy.config['css_mtime']}" />
href="/gutenberg/pg-desktop-one.css?${cherrypy.config['css_mtime']}" />
<link rel="stylesheet" type="text/css"
href="/gutenberg/new_nav.css?${cherrypy.config['css_mtime']}"/>
<link rel="stylesheet" type="text/css"
href="/gutenberg/style.css?${cherrypy.config['css_mtime']}"/>
<script type="text/javascript">//<![CDATA[
//<![CDATA[
var json_search = "/ebooks/suggest/";
var mobile_url = "//m.gutenberg.org/ebooks.mobile/";
var canonical_url = "https://www.gutenberg.org/ebooks/";
var lang = "en";
var fb_lang = "en_US"; /* FB accepts only xx_XX */
@ -27,7 +35,7 @@
//]]></script>
<script type="text/javascript"
src="/js/pg-desktop-one.js?${cherrypy.config['js_mtime']}" />
<link rel="shortcut icon" href="/pics/favicon" />
<link rel="shortcut icon" href="/gutenberg/favicon" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="Content-Style-Type" content="text/css" />
@ -36,99 +44,22 @@
<title>${os.message}</title>
</head>
<body>
<div id="mw-head-dummy" class="noprint" />
<div id="content" i18n:comment="On the page of results of a search.">
<div class="header">
<div class="container">
${site_top()}
<div id="page_content" i18n:comment="error page." style="margin-top: 4em">
<h1>${os.message}</h1>
</div>
<div class="body">
<div class="page-body">
</div>
</div>
<div id="fb-root" />
<div id="print-head" class="noscreen">
<div class="center">Project Gutenberg offers thousands of free ebooks to download.</div>
</div>
<div id="screen-head" class="noprint">
<table>
<tr i18n:comment="The logo, tagline and badges at the very top of every page.">
<td rowspan="2" id="logo" i18n:comment="The PG logo at the top left of every page.">
<a href="/wiki/Main_Page" title="Go to the Main Page.">
<span class="icon icon_logo" />
</a>
</td>
<td id="tagline-badges" colspan="2">
<table>
<tr>
<td id="tagline">Project Gutenberg offers thousands of free ebooks to download.</td>
</tr>
</table>
</td>
</tr>
<tr id="menubar-search">
<td id="menubar" i18n:comment="The menu bar at the top of every page.">
<a id="menubar-first"
tabindex="11" accesskey="1"
title="Start a new search."
href="/ebooks/">Search</a>
<a tabindex="22"
title="Our latest releases."
href="/ebooks/search/?sort_order=release_date">Latest</a>
<a tabindex="31"
title="Read the Project Gutenberg terms of use."
href="/terms_of_use/">Terms of Use</a>
<a tabindex="32"
href="/wiki/Gutenberg:Project_Gutenberg_Needs_Your_Donation"
title="Learn why we need some money.">Donate?</a>
</td>
<td id="search" i18n:comment="The search box at the top right of every page.">
<form method="get" action="/ebooks/search/"
enctype="multipart/form-data">
<table class="borderless">
<tr>
<td id="search-button-cell">
<button id="search-button" type="submit" title="Execute the search. &lt;enter&gt;">
<span class="icon icon_smsearch" />
</button>
</td>
<td id="search-input-cell">
<input id="search-input" name="query" type="text" title="Search Project Gutenberg. &lt;s&gt;"
accesskey="s" value="" />
</td>
<td id="help-button-cell">
<button id="help-button" type="button" title="Open the help menu. &lt;h&gt;"
accesskey="h">Help</button>
</td>
</tr>
</table>
</form>
</td>
</tr>
</table>
<div id="helpbox" class="hide">
<xi:include href="help.html" />
</div>
</div>
</body>
</html>

View File

@ -66,7 +66,7 @@ which contains *all* Project Gutenberg metadata in one RDF/XML file.
<body>
<div id="mw-head-dummy" class="noprint" />
<div id="content" i18n:comment="On the page of results of a search.">
<div id="content" class="page_content" i18n:comment="On the page of results of a search.">
<div class="header">
<h1><span class="icon icon_${os.title_icon}" />${os.title}</h1>
</div>

View File

@ -1,151 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
DON'T USE THIS PAGE FOR SCRAPING.
Seriously. You'll only get your IP blocked.
Download https://www.gutenberg.org/feeds/catalog.rdf.bz2 instead,
which contains *all* Project Gutenberg metadata in one RDF/XML file.
-->
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:py="http://genshi.edgewall.org/"
xmlns:i18n="http://genshi.edgewall.org/i18n"
xml:lang="${os.lang}">
<?python
import re
from libgutenberg import GutenbergGlobals as gg
old_header = ''
def help_page (s = ''):
s = s.replace (' ', '_')
return '%s#%s' % ('/wiki/Gutenberg:Help_on_Bibliographic_Record_Page', s)
?>
<xi:include href="site-layout.mobile" />
<head profile="http://a9.com/-/spec/opensearch/1.1/">
${site_head ()}
<title>${os.title}</title>
<meta name="totalResults" content="${os.total_results}" />
<meta name="startIndex" content="${os.start_index}" />
<meta name="itemsPerPage" content="${os.items_per_page}" />
</head>
<body>
<div class="content" i18n:comment="On the page of results of a search.">
<ol class="results">
${search_box ()}
<py:for each="n, e in enumerate (os.entries)">
<py:if test="e.header and old_header != e.header">
<li class="header">${e.header}</li>
</py:if>
<?python old_header = e.header ?>
<py:if test="isinstance (e, bs.DC)">
<li class="bibrec">
<div class="table">
<div class="row">
<div class="cell leftcell">
<div class="icon icon_${e.icon}" />
</div>
<div class="cell content">
<!--! get coverpage first, it floats to the right -->
<img py:if="e.cover_image" class="coverpage"
src="${e.cover_image.url}" alt="[Coverpage]" />
<p py:for="author in e.authors">${author.role}: ${author.name_and_dates}</p>
<py:for each="marc in e.marcs">
<py:choose test="">
<p py:when="marc.code[0]=='5'">
<?python
text = gg.xmlspecialchars (marc.text)
text = re.sub (r'(//\S+)', r'<a href="\1">\1</a>', text)
text = re.sub (r'#(\d+)',
r'<a href="/ebooks/\1.mobile">#\1</a>', text)
?>
${marc.caption}:
${ Markup (gg.insert_breaks (text)) }
</p>
<p py:otherwise="">
${marc.caption}:
${ Markup (gg.insert_breaks (gg.xmlspecialchars (marc.text))) }
</p>
</py:choose>
</py:for>
<p>Ebook No.: ${e.project_gutenberg_id}</p>
<p>Published: ${e.hr_release_date}</p>
<p>Downloads: ${e.downloads}</p>
<p py:for="language in e.languages">Language: ${language.language}</p>
<p py:for="subject in e.subjects">Subject: ${subject.subject}</p>
<p py:for="locc in e.loccs">LoCC: ${locc.locc}</p>
<p py:for="category in e.categories">Category: ${category}</p>
<p>Rights: ${e.rights}</p>
</div>
</div>
</div>
</li>
</py:if>
<py:if test="isinstance (e, bs.Cat)">
<py:choose test="">
<py:when test="e.rel == '__statusline__'" />
<py:otherwise>
<li class="${e.class_}">
<a class="table link" href="${e.url}" accesskey="${str (n % 10)}">
<span class="row">
<span class="cell leftcell">
<span class="icon icon_${e.icon}" />
</span>
<span class="cell content">
<span py:if="e.title" class="title">${e.title}</span>
<span py:if="e.subtitle" class="subtitle">${e.subtitle}</span>
<span py:if="e.extra" class="extra">${e.extra}</span>
</span>
<span py:if="e.icon2" class="cell rightcell">
<span class="icon icon_${e.icon2}" />
</span>
</span>
</a>
</li>
</py:otherwise>
</py:choose>
</py:if>
</py:for>
<py:if test="os.show_next_page_link">
<li class="navlink more grayed">
<a class="table link"
href="${os.url_carry (start_index = os.next_page_index)}">
<span class="row">
<span class="cell leftcell">
<span class="icon icon_more" />
</span>
<span class="cell content">
<span class="title"><span>Next Page</span>…</span>
</span>
<span class="cell rightcell">
<span class="icon spinner" />
</span>
</span>
</a>
</li>
</py:if>
</ol>
</div>
${site_footer ()}
</body>
</html>

View File

@ -16,12 +16,15 @@
</style>
<link rel="stylesheet" type="text/css"
href="/css/pg-desktop-one.css?${cherrypy.config['css_mtime']}" />
href="/gutenberg/pg-desktop-one.css?${cherrypy.config['css_mtime']}" />
<link rel="stylesheet" type="text/css"
href="/gutenberg/new_nav.css?${cherrypy.config['css_mtime']}"/>
<link rel="stylesheet" type="text/css"
href="/gutenberg/style.css?${cherrypy.config['css_mtime']}"/>
<!--! IE8 does not recognize application/javascript -->
<script>//<![CDATA[
var json_search = "${os.json_search}";
var mobile_url = "${os.mobile_url}";
var canonical_url = "${os.canonical_url}";
var lang = "${os.lang}";
var fb_lang = "${os.fb_lang}"; /* FB accepts only xx_XX */
@ -34,7 +37,7 @@
<script
src="/js/pg-desktop-one.js?${cherrypy.config['js_mtime']}" />
<link rel="shortcut icon" href="/pics/favicon" />
<link rel="shortcut icon" href="/gutenberg/favicon" />
<link rel="canonical" href="${os.canonical_url}" />
<link rel="search"
@ -110,99 +113,12 @@
<py:def function="copyright">
<div class="copyright" i18n:comment="The copyright notice on the footer of every page.">
© 20032019 Project Gutenberg Literary Archive Foundation — All Rights Reserved.
© 2020 Project Gutenberg Literary Archive Foundation — All Rights Reserved.
</div>
</py:def>
<py:def function="site_top">
<div id="fb-root" />
<div id="print-head" class="noscreen">
<div class="center">${os.desktop_url}<br/><br/>${os.tagline}</div>
</div>
<div id="screen-head" class="noprint">
<table>
<tr i18n:comment="The logo, tagline and badges at the very top of every page.">
<td rowspan="2" id="logo" i18n:comment="The PG logo at the top left of every page.">
<a href="/wiki/Main_Page" title="Go to the Main Page.">
<span class="icon icon_logo" />
</a>
</td>
<td id="tagline-badges" colspan="2">
<table>
<tr>
<td id="tagline">${os.tagline}</td>
<td id="paypal-badge" class="badge">${paypal ()}</td>
<td id="flattr-badge" class="badge">${flattr ()}</td>
</tr>
</table>
</td>
</tr>
<tr id="menubar-search">
<td id="menubar" i18n:comment="The menu bar at the top of every page.">
<a py:if="os.page != 'start'"
id="menubar-first"
tabindex="11" accesskey="1"
title="Start a new search."
href="${os.url ('start')}">Search</a>
<span py:if="os.page == 'start'"
id="menubar-first" class="grayed">Search</span>
<a tabindex="22"
title="Our latest releases."
href="/ebooks/search/?sort_order=release_date">Latest</a>
<a tabindex="31"
title="Read the Project Gutenberg terms of use."
href="/terms_of_use/">Terms of Use</a>
<a tabindex="32"
href="/wiki/Gutenberg:Project_Gutenberg_Needs_Your_Donation"
title="Learn why we need some money.">Donate?</a>
<a tabindex="33" accesskey="m" href="${os.mobile_url}"
title="Go to our mobile site.">Mobile</a>
</td>
<td id="search" i18n:comment="The search box at the top right of every page.">
<form method="get" action="${os.desktop_search}"
enctype="multipart/form-data">
<table class="borderless">
<tr>
<td id="search-button-cell">
<button id="search-button" type="submit" title="Execute the search. &lt;enter&gt;">
<span class="icon icon_smsearch" />
</button>
</td>
<td id="search-input-cell">
<input id="search-input" name="query" type="text" title="${os.placeholder} &lt;s&gt;"
accesskey="s" value="${os.search_terms}" />
</td>
<td id="help-button-cell">
<button id="help-button" type="button" title="Open the help menu. &lt;h&gt;"
accesskey="h">Help</button>
</td>
</tr>
</table>
</form>
</td>
</tr>
</table>
<div id="helpbox" class="hide">
<xi:include href="help.html" />
</div>
</div>
<xi:include href="../../menu.html" />
</py:def>
<py:def function="site_footer">

View File

@ -1,124 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:py="http://genshi.edgewall.org/"
xmlns:i18n="http://genshi.edgewall.org/i18n"
py:strip="">
<?python
from i18n_tool import ugettext as _
?>
<py:def function="site_head">
<style >
.icon { background: transparent url(/pics/sprite.png?${cherrypy.config['css_mtime']}) 0 0 no-repeat; }
</style>
<link rel="stylesheet" type="text/css"
href="/css/pg-mobile-one.css?${cherrypy.config['css_mtime']}" />
<script type="application/javascript"><![CDATA[
var mobile_search = "${os.add_amp (os.mobile_search)}query=";
var json_search = "${os.json_search}";
var msg_load_more = "${_('Load More Results…')}";
var do_animations = ${'true' if os.do_animations else 'false'};
]]>
</script>
<script type="application/javascript"
src="/js/pg-mobile-one.js?${cherrypy.config['js_mtime']}" />
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
<meta http-equiv="Content-Style-Type" content="text/css" />
<meta http-equiv="Content-Language" content="${os.lang}" />
<meta name="description" content="The Project Gutenberg ebook catalog for mobile devices." />
<meta name="keywords" content="free ebooks, free books, free audio books" />
<meta name="classification" content="public" />
<link rel="icon" href="/pics/favicon" />
<link rel="canonical" href="${os.canonical_url}" />
<link rel="search"
type="application/opensearchdescription+xml"
title="Search Project Gutenberg"
href="${os.osd_url}" />
<link rel="alternate nofollow"
type="${os.type_opds}"
title="OPDS feed"
href="${os.url_carry (format = 'opds')}" />
<link py:if="os.touch_icon" rel="apple-touch-icon" href="${os.touch_icon}" />
<link py:if="os.touch_icon_precomposed" rel="apple-touch-icon-precomposed" href="${os.touch_icon_precomposed}" />
<meta py:if="os.viewport" name="viewport" content="${os.viewport}" />
</py:def>
<py:def function="search_box">
<li class="grayed" id="searchlist">
<div class="table link">
<div class="row">
<div class="cell leftcell">
<div class="icon icon_search" />
</div>
<div class="cell content">
<form id="search" method="get" action="${os.mobile_search}"
enctype="multipart/form-data">
<div id="query-clear-wrapper">
<div id="query-wrapper">
<input id="query" name="query"
type="text"
inputmode="latin"
value="${os.search_terms}"
title="${os.placeholder}" />
</div>
</div>
</form>
</div>
<!--! <div class="cell cancelcell">
<button type="reset" id="clear" class="icon icon_cancel"
title="Clear" i18n:comment="Reset Form Button" />
</div> -->
<div class="cell rightcell">
<button type="button" id="help"
title="Help" onclick="toggle_help ()" i18n:comment="Help about search button">
<div class="icon icon_help" />
</button>
</div>
</div>
</div>
</li>
<li class="grayed" id="helpbox"
style="display: none" onclick="clear_help ()">
<div class="helpbox">
<xi:include href="help.html" />
</div>
</li>
<py:if test="os.page != 'start' and os.start_index == 1">
<li class="navlink grayed">
<a class="table link" href="${os.url ('start')}" accesskey="h">
<span class="row">
<span class="cell leftcell">
<span class="icon icon_internal" />
</span>
<span class="cell content">
<span class="title">Search Start Page</span>
</span>
<span class="cell rightcell">
<span class="icon icon_next" />
</span>
</span>
</a>
</li>
</py:if>
</py:def>
<py:def function="site_footer">
<div class="footer">
<div class="copyright">
© 20032012 Project Gutenberg Literary Archive Foundation — All Rights Reserved.
</div>
</div>
</py:def>
</html>

View File

@ -10,48 +10,40 @@
<?python
from six.moves import urllib
def p (params):
return urllib.parse.urlencode (params).replace ('+', '%20')
def p(params):
return urllib.parse.urlencode(params).replace('+', '%20')
?>
<py:def function="fb_share(url, title, description, picture)">
<py:def function="fb_share(url)">
<?python
params = {
'link': url,
'app_id': cherrypy.config['facebook_app_id'],
'name': title,
'description': description,
'redirect_uri': 'https://www.gutenberg.org/fb_redirect.html',
'u': url,
}
if picture is not None:
params['picture'] = picture
?>
<div class="social-button fb-share-button" i18n:comment="Share on Facebook.">
<a href="https://www.facebook.com/dialog/feed?${p (params)}"
<div class="social-button fb-share-button">
<a href="https://www.facebook.com/sharer.php?${p(params)}"
title="Share on Facebook"
onclick="open_share_popup(this.href, this.target, 1024, 560)" target="_fb_share_popup">
onclick="open_share_popup(this.href, this.target, 640, 320)"
target="_top">
<span class="icon icon_facebook" />
</a>
</div>
</py:def>
<py:def function="tw_share(url, text)">
<!-- tweet without javascript -->
<?python
params = {
'url': url,
'text': text.encode ('utf-8'),
'text': text.encode('utf-8'),
'count': 'none',
'lang': os.twitter_lang,
'related': "gutenberg_new:Project Gutenberg New Books"
}
?>
<div class="social-button twitter-share-button">
<!--! https://dev.twitter.com/docs/tweet-button -->
<a href="https://twitter.com/share?${p (params)}"
<a href="https://twitter.com/share?${p(params)}"
title="Share on Twitter"
onclick="open_share_popup(this.href, this.target, 640, 320)"
target="_top">