rip out all mobile site remnants
parent
9c8f030218
commit
c2833335b9
|
@ -43,7 +43,7 @@ VALID_PROTOCOLS = ('http', 'https')
|
||||||
|
|
||||||
MEDIATYPE_TO_FORMAT = {
|
MEDIATYPE_TO_FORMAT = {
|
||||||
'text/html' : 'html',
|
'text/html' : 'html',
|
||||||
mt.mobile : 'mobile',
|
mt.mobile : 'html',
|
||||||
mt.opds : 'opds',
|
mt.opds : 'opds',
|
||||||
mt.json : 'json',
|
mt.json : 'json',
|
||||||
}
|
}
|
||||||
|
@ -101,54 +101,6 @@ class ClassAttr (object):
|
||||||
return b in self.value
|
return b in self.value
|
||||||
|
|
||||||
|
|
||||||
class Accumulator (object):
|
|
||||||
"""
|
|
||||||
Thread-safe master/slave counter for statistics collection.
|
|
||||||
|
|
||||||
Many serving threads can increment the master counter
|
|
||||||
while the statistic thread safely reads the slave counter.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__ (self):
|
|
||||||
self.master = defaultdict (int)
|
|
||||||
self.slave = defaultdict (int)
|
|
||||||
self.lock = threading.Lock ()
|
|
||||||
|
|
||||||
def increment (self, key):
|
|
||||||
""" Thread-safe increment the master counter. """
|
|
||||||
try:
|
|
||||||
self.lock.acquire ()
|
|
||||||
self.master[key] += 1
|
|
||||||
finally:
|
|
||||||
self.lock.release ()
|
|
||||||
|
|
||||||
def reset (self):
|
|
||||||
""" Copy values to slave counter and reset the master counter. """
|
|
||||||
try:
|
|
||||||
self.lock.acquire ()
|
|
||||||
self.slave = self.master.copy ()
|
|
||||||
self.master.clear ()
|
|
||||||
finally:
|
|
||||||
self.lock.release ()
|
|
||||||
|
|
||||||
def __getitem__ (self, k):
|
|
||||||
""" Read value from the slave counter. """
|
|
||||||
return self.slave[k]
|
|
||||||
|
|
||||||
def iter_results (self):
|
|
||||||
""" Iterate over the slave counters. """
|
|
||||||
|
|
||||||
total_hits = float (sum (self.slave.values ()))
|
|
||||||
if total_hits > 0:
|
|
||||||
for k, v in sorted (self.slave.items (), key = lambda x: -x[1]):
|
|
||||||
yield (k, v, v / total_hits)
|
|
||||||
|
|
||||||
|
|
||||||
formats_acc = Accumulator ()
|
|
||||||
formats_sum_acc = Accumulator ()
|
|
||||||
|
|
||||||
|
|
||||||
class DC (GutenbergDatabaseDublinCore.GutenbergDatabaseDublinCore,
|
class DC (GutenbergDatabaseDublinCore.GutenbergDatabaseDublinCore,
|
||||||
DublinCoreI18n.DublinCoreI18nMixin):
|
DublinCoreI18n.DublinCoreI18nMixin):
|
||||||
""" A localized DublinCore. """
|
""" A localized DublinCore. """
|
||||||
|
@ -491,12 +443,6 @@ class OpenSearch (object):
|
||||||
except ValueError as what:
|
except ValueError as what:
|
||||||
raise cherrypy.HTTPError (400, 'Bad Request. ' + str (what))
|
raise cherrypy.HTTPError (400, 'Bad Request. ' + str (what))
|
||||||
|
|
||||||
formats_acc.increment (self.format)
|
|
||||||
|
|
||||||
if self.format in ('mobile', 'opds', 'stanza'):
|
|
||||||
formats_sum_acc.increment ('mobile')
|
|
||||||
if self.format == 'html':
|
|
||||||
formats_sum_acc.increment ('html')
|
|
||||||
|
|
||||||
self.file_host = cherrypy.config['file_host']
|
self.file_host = cherrypy.config['file_host']
|
||||||
self.now = datetime.datetime.utcnow ().replace (microsecond = 0).isoformat () + 'Z'
|
self.now = datetime.datetime.utcnow ().replace (microsecond = 0).isoformat () + 'Z'
|
||||||
|
@ -594,7 +540,6 @@ class OpenSearch (object):
|
||||||
self.viewport = None
|
self.viewport = None
|
||||||
|
|
||||||
self.desktop_host = cherrypy.config['host']
|
self.desktop_host = cherrypy.config['host']
|
||||||
self.mobile_host = cherrypy.config['host_mobile']
|
|
||||||
|
|
||||||
last_page = max ((self.total_results - 1) // self.items_per_page, 0) # 0-based
|
last_page = max ((self.total_results - 1) // self.items_per_page, 0) # 0-based
|
||||||
|
|
||||||
|
@ -608,7 +553,6 @@ class OpenSearch (object):
|
||||||
self.show_next_page_link = (self.end_index < self.total_results)
|
self.show_next_page_link = (self.end_index < self.total_results)
|
||||||
|
|
||||||
self.desktop_search = self.url ('search', format = None)
|
self.desktop_search = self.url ('search', format = None)
|
||||||
self.mobile_search = self.url ('search', format = 'mobile')
|
|
||||||
self.json_search = self.url ('suggest', format = None)
|
self.json_search = self.url ('suggest', format = None)
|
||||||
|
|
||||||
self.base_url = self.url (host = self.file_host)
|
self.base_url = self.url (host = self.file_host)
|
||||||
|
@ -617,7 +561,6 @@ class OpenSearch (object):
|
||||||
self.canonical_url = self.url_carry (host = self.file_host, format = None)
|
self.canonical_url = self.url_carry (host = self.file_host, format = None)
|
||||||
|
|
||||||
self.desktop_url = self.url_carry (host = self.desktop_host, format = None)
|
self.desktop_url = self.url_carry (host = self.desktop_host, format = None)
|
||||||
self.mobile_url = self.url_carry (host = self.mobile_host, format = 'mobile')
|
|
||||||
|
|
||||||
self.osd_url = self.qualify ('/catalog/osd-books.xml')
|
self.osd_url = self.qualify ('/catalog/osd-books.xml')
|
||||||
|
|
||||||
|
@ -704,7 +647,7 @@ class OpenSearch (object):
|
||||||
|
|
||||||
# user explicitly requested format
|
# user explicitly requested format
|
||||||
if format_:
|
if format_:
|
||||||
self.format = format_
|
self.format = 'html' if format_ == 'mobile' else format_
|
||||||
self.mediatype = mt[format_]
|
self.mediatype = mt[format_]
|
||||||
self.opensearch_support = 1 if format_ == 'opds' else 2
|
self.opensearch_support = 1 if format_ == 'opds' else 2
|
||||||
return
|
return
|
||||||
|
@ -713,32 +656,11 @@ class OpenSearch (object):
|
||||||
|
|
||||||
ua = self.user_agent
|
ua = self.user_agent
|
||||||
|
|
||||||
# user accessed the www site
|
|
||||||
|
|
||||||
if self.host == cherrypy.config['host']:
|
|
||||||
# but might want the mobile site ...
|
|
||||||
if 'Kindle/' in ua:
|
|
||||||
self.format = 'mobile'
|
|
||||||
self.mediatype = mt.mobile
|
|
||||||
elif 'tolino' in ua:
|
|
||||||
self.format = 'mobile'
|
|
||||||
self.mediatype = mt.mobile
|
|
||||||
elif ua.startswith ('W3C-mobileOK/DDC-1.0'):
|
|
||||||
self.format = 'mobile'
|
|
||||||
self.mediatype = mt.mobile
|
|
||||||
else:
|
|
||||||
self.format = 'html'
|
self.format = 'html'
|
||||||
self.mediatype = 'text/html'
|
self.mediatype = 'text/html'
|
||||||
return
|
|
||||||
|
|
||||||
# user accessed the mobile site
|
# user accessed the mobile site
|
||||||
|
|
||||||
mediatype = None
|
|
||||||
|
|
||||||
if self.host == cherrypy.config['host_mobile']:
|
|
||||||
format_ = 'mobile'
|
|
||||||
mediatype = mt.mobile
|
|
||||||
|
|
||||||
# known OPDS consumers
|
# known OPDS consumers
|
||||||
# 'stanza' is the older opds-ish format supported by stanza et al.
|
# 'stanza' is the older opds-ish format supported by stanza et al.
|
||||||
|
|
||||||
|
@ -795,11 +717,6 @@ class OpenSearch (object):
|
||||||
mediatype = mt.opds
|
mediatype = mt.opds
|
||||||
opensearch_support = 1
|
opensearch_support = 1
|
||||||
|
|
||||||
# still nothing?
|
|
||||||
if not format_:
|
|
||||||
mediatype = 'text/html'
|
|
||||||
format_ = 'html'
|
|
||||||
|
|
||||||
self.format = format_
|
self.format = format_
|
||||||
self.mediatype = mediatype
|
self.mediatype = mediatype
|
||||||
self.opensearch_support = opensearch_support
|
self.opensearch_support = opensearch_support
|
||||||
|
|
|
@ -19,7 +19,6 @@ pgdatabase: 'gutenberg'
|
||||||
pguser: 'postgres'
|
pguser: 'postgres'
|
||||||
|
|
||||||
host: 'www.gutenberg.org'
|
host: 'www.gutenberg.org'
|
||||||
host_mobile: 'm.gutenberg.org'
|
|
||||||
host_https: 1
|
host_https: 1
|
||||||
file_host: 'www.gutenberg.org'
|
file_host: 'www.gutenberg.org'
|
||||||
|
|
||||||
|
|
|
@ -87,7 +87,6 @@ def main():
|
||||||
'daemonize': False,
|
'daemonize': False,
|
||||||
'pidfile': None,
|
'pidfile': None,
|
||||||
'host': 'localhost',
|
'host': 'localhost',
|
||||||
'host_mobile': 'localhost',
|
|
||||||
'file_host': 'localhost',
|
'file_host': 'localhost',
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -31,9 +31,6 @@ from i18n_tool import ugettext as _
|
||||||
# filetypes ignored on desktop site
|
# filetypes ignored on desktop site
|
||||||
NO_DESKTOP_FILETYPES = 'plucker qioo rdf rst rst.gen rst.master tei cover.medium cover.small'.split ()
|
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
|
# filetypes which are usually handed over to a separate app on mobile devices
|
||||||
HANDOVER_TYPES = (mt.epub, mt.mobi, mt.pdf)
|
HANDOVER_TYPES = (mt.epub, mt.mobi, mt.pdf)
|
||||||
|
|
||||||
|
@ -187,44 +184,3 @@ class HTMLFormatter (XMLishFormatter):
|
||||||
if showncount == 0:
|
if showncount == 0:
|
||||||
for file_ in dc.files + dc.generated_files:
|
for file_ in dc.files + dc.generated_files:
|
||||||
file_.hidden = False
|
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)
|
|
||||||
|
|
|
@ -265,7 +265,7 @@ class AuthorPage (SearchPage):
|
||||||
os.entries.insert (0, cat)
|
os.entries.insert (0, cat)
|
||||||
|
|
||||||
# author aliases
|
# author aliases
|
||||||
if os.format in ('html', 'mobile'):
|
if os.format == 'html':
|
||||||
rows = BaseSearcher.SQLSearcher.execute (
|
rows = BaseSearcher.SQLSearcher.execute (
|
||||||
"""SELECT alias AS title FROM aliases
|
"""SELECT alias AS title FROM aliases
|
||||||
WHERE fk_authors = %(fk_authors)s AND alias_heading = 1""",
|
WHERE fk_authors = %(fk_authors)s AND alias_heading = 1""",
|
||||||
|
|
|
@ -30,7 +30,6 @@ class Start (Page.Page):
|
||||||
|
|
||||||
os.search_terms = ''
|
os.search_terms = ''
|
||||||
os.title = {
|
os.title = {
|
||||||
'mobile': _('PG Mobile'),
|
|
||||||
'opds': _('Project Gutenberg'),
|
'opds': _('Project Gutenberg'),
|
||||||
'stanza': _('Project Gutenberg')
|
'stanza': _('Project Gutenberg')
|
||||||
}.get (os.format, _('Search Project Gutenberg'))
|
}.get (os.format, _('Search Project Gutenberg'))
|
||||||
|
|
|
@ -25,7 +25,6 @@
|
||||||
<script type="text/javascript">//<![CDATA[
|
<script type="text/javascript">//<![CDATA[
|
||||||
//<![CDATA[
|
//<![CDATA[
|
||||||
var json_search = "/ebooks/suggest/";
|
var json_search = "/ebooks/suggest/";
|
||||||
var mobile_url = "https://www.gutenberg.org/ebooks/";
|
|
||||||
var canonical_url = "https://www.gutenberg.org/ebooks/";
|
var canonical_url = "https://www.gutenberg.org/ebooks/";
|
||||||
var lang = "en";
|
var lang = "en";
|
||||||
var fb_lang = "en_US"; /* FB accepts only xx_XX */
|
var fb_lang = "en_US"; /* FB accepts only xx_XX */
|
||||||
|
|
|
@ -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>
|
|
|
@ -26,7 +26,6 @@
|
||||||
<script>//<![CDATA[
|
<script>//<![CDATA[
|
||||||
var json_search = "${os.json_search}";
|
var json_search = "${os.json_search}";
|
||||||
var canonical_url = "${os.canonical_url}";
|
var canonical_url = "${os.canonical_url}";
|
||||||
var mobile_url = "${os.canonical_url}";
|
|
||||||
var lang = "${os.lang}";
|
var lang = "${os.lang}";
|
||||||
var fb_lang = "${os.fb_lang}"; /* FB accepts only xx_XX */
|
var fb_lang = "${os.fb_lang}"; /* FB accepts only xx_XX */
|
||||||
var msg_load_more = "${_('Load More Results…')}";
|
var msg_load_more = "${_('Load More Results…')}";
|
||||||
|
|
Loading…
Reference in New Issue