autocat3/OPDSFormatter.py

161 lines
4.8 KiB
Python

#!/usr/bin/env python
# -*- mode: python; indent-tabs-mode: nil; -*- coding: iso-8859-1 -*-
"""
OPDSFormatter.py
Copyright 2009-2012 by Marcello Perathoner
Distributable under the GNU General Public License Version 3 or newer.
Produce an OPDS feed.
"""
from __future__ import unicode_literals
import copy
import re
import genshi.output
import cherrypy
import six
from libgutenberg.GutenbergGlobals import Struct, xmlspecialchars
from libgutenberg.MediaTypes import mediatypes as mt
from libgutenberg import DublinCore
import BaseFormatter
from Icons import THUMBS as th
# files a mobile can download
OPDS_TYPES = (mt.epub, mt.mobi, mt.pdf)
# domains allowed to XMLHttpRequest () our OPDS feed
CORS_DOMAINS = '*'
class OPDSFormatter (BaseFormatter.BaseFormatter):
""" Produces opds output. """
CONTENT_TYPE = mt.opds + '; charset=UTF-8'
DOCTYPE = None
def get_serializer (self):
return genshi.output.XMLSerializer (doctype = self.DOCTYPE, strip_whitespace = False)
def send_headers (self):
""" Send HTTP content-type header. """
cherrypy.response.headers['Access-Control-Allow-Origin'] = CORS_DOMAINS
super (OPDSFormatter, self).send_headers ()
def format (self, page, os):
""" Format os struct into opds output. """
entries = []
for dc in os.entries:
dc.thumbnail = None
if isinstance (dc, DublinCore.DublinCore):
dc.image_flags = 0
if dc.has_images ():
dc.pool = None
dc_copy = copy.deepcopy (dc)
dc.image_flags = 2
dc.icon = 'title_no_images'
self.fix_dc (dc, os)
entries.append (dc)
dc_copy.image_flags = 3
self.fix_dc (dc_copy, os, True)
entries.append (dc_copy)
else:
self.fix_dc (dc, os)
entries.append (dc)
else:
# actually not a dc
# throw out 'start over' link, FIXME: actually throw out all non-dc's ?
if page == 'bibrec' and dc.rel == 'start':
continue
dc.links = []
if dc.icon in th:
link = Struct ()
link.type = mt.png
link.rel = 'thumb'
link.url = self.data_url (th[dc.icon])
link.title = None
link.length = None
dc.links.append (link)
entries.append (dc)
os.entries = entries
if page == 'bibrec':
# we have just one template for both
page = 'results'
return self.render (page, os)
def fix_dc (self, dc, os, want_images = False):
""" Make fixes to dublincore struct. """
def to_html (text):
""" Turn plain text into html. """
return re.sub (r'[\r\n]+', '<br/>', xmlspecialchars (text))
def key_role (author):
""" Sort authors first, then other contributors. """
if author.marcrel in ('cre', 'aut'):
return ''
return author.marcrel
super (OPDSFormatter, self).fix_dc (dc, os)
if dc.icon in th:
dc.thumbnail = self.data_url (th[dc.icon])
dc.links = []
dc.title_html = to_html (dc.title)
dc.authors.sort (key = key_role)
for file_ in dc.files + dc.generated_files:
if len (file_.mediatypes) == 1:
type_ = six.text_type (file_.mediatypes[0])
filetype = file_.filetype or ''
if type_.partition (';')[0] in OPDS_TYPES:
if ((filetype.find ('.images') > -1) == want_images):
link = Struct ()
link.type = type_
link.title = file_.hr_filetype
link.url = file_.url
link.length = str (file_.extent)
link.rel = 'acquisition'
dc.links.append (link)
if filetype == 'cover.small':
link = Struct ()
link.type = six.text_type (file_.mediatypes[0])
link.title = None
link.url = file_.url
link.length = None
link.rel = 'thumb'
dc.links.append (link)
if filetype == 'cover.medium':
link = Struct ()
link.type = six.text_type (file_.mediatypes[0])
link.title = None
link.url = file_.url
link.length = None
link.rel = 'cover'
dc.links.append (link)