forked from gutenbergtools/autocat3
-
-
Notifications
You must be signed in to change notification settings - Fork 1
/
OPDSFormatter.py
160 lines (118 loc) · 4.79 KB
/
OPDSFormatter.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#!/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)