-
Notifications
You must be signed in to change notification settings - Fork 589
/
Copy pathbookcontainer.py
484 lines (371 loc) · 17.5 KB
/
bookcontainer.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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab
# Copyright (c) 2015-2020 Kevin B. Hendricks, and Doug Massay
# Copyright (c) 2014 Kevin B. Hendricks, John Schember, and Doug Massay
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this list of
# conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice, this list
# of conditions and the following disclaimer in the documentation and/or other materials
# provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
# SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
# WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from quickparser import QuickXHTMLParser
from preferences import JSONPrefs
from pluginhunspell import HunspellChecker
class ContainerException(Exception):
pass
class BookContainer(object):
def __init__(self, wrapper, debug=False):
self._debug = debug
self._w = wrapper
self.qp = QuickXHTMLParser()
self.hspell = HunspellChecker(wrapper.get_hunspell_path())
self.dictionary_dirs = wrapper.get_dictionary_dirs()
self._prefs_store = JSONPrefs(wrapper.plugin_dir, wrapper.plugin_name)
def getPrefs(self):
return self._prefs_store
def savePrefs(self, user_copy):
self._prefs_store = user_copy
self._prefs_store._commit()
def launcher_version(self):
return self._w.getversion()
def epub_version(self):
return self._w.getepubversion()
def epub_is_standard(self):
return self._w.epub_is_standard()
@property
def sigil_ui_lang(self):
if self._w.sigil_ui_lang is None:
return 'en'
return self._w.sigil_ui_lang
@property
def sigil_spellcheck_lang(self):
if self._w.sigil_spellcheck_lang is None:
return 'en_US'
return self._w.sigil_spellcheck_lang
# OPF Acess and Manipulation Routines
# toc and pagemap access routines
def gettocid(self):
return self._w.gettocid()
def getpagemapid(self):
return self._w.getpagemapid()
# nav access routines
def getnavid(self):
return self._w.getnavid()
# spine get/set and access routines
def getspine(self):
# spine is an ordered list of tuples (id, linear)
return self._w.getspine()
def setspine(self, new_spine):
# new_spine must be an ordered list of tuples (id, linear)
self._w.setspine(new_spine)
# New for epub3
def getspine_epub3(self):
# spine is an ordered list of tuples (id, linear, properties)
return self._w.getspine_epub3()
# New for epub3
def setspine_epub3(self, new_spine):
# new_spine must be an ordered list of tuples (id, linear, properties (or None))
self._w.setspine_epub3(new_spine)
# Modified for epub3
# Note: for prepend, set pos = 0
# for append, set pos = -1 or pos >= current length of spine
def spine_insert_before(self, pos, spid, linear, properties=None):
self._w.spine_insert_before(pos, spid, linear, properties)
def getspine_ppd(self):
# spine_ppd is utf-8 string of page direction (rtl, ltr, None)
return self._w.getspine_ppd()
def setspine_ppd(self, ppd):
# new pagedirection string
self._w.setspine_ppd(ppd)
# New for epub3
def setspine_idref_epub3_attributes(self, idref, linear, properties):
self._w.setspine_idref_attributes(idref, linear, properties)
# guide get/set
def getguide(self):
# guide is an ordered list of tuples (type, title, href)
return self._w.guide
def setguide(self, new_guide):
# new_guide must be an ordered list of tupes (type, title, href)
self._w.setguide(new_guide)
# bindings get/set access routines
# New for epub3
def getbindings_epub3(self):
# bindings is an ordered list of tuples (media-type, handler)
return self._w.getbindings_epub3()
# New for epub3
def setbindings_epub3(self, new_bindings):
# new_bindings is an ordered list of tuples (media-type, handler)
self._w.setbindings_epub3(new_bindings)
# metadata get/set
def getmetadataxml(self):
# returns a utf-8 encoded metadata xml fragement
return self._w.getmetadataxml()
def setmetadataxml(self, new_metadata):
# new_metadata must be a metadata xml fragmment
self._w.setmetadataxml(new_metadata)
# package tag get/set
def getpackagetag(self):
# returns a utf-8 encoded metadata xml fragement
return self._w.getpackagetag()
def setpackagetag(self, new_tag):
# new_tag must be a xml package tag
self._w.setpackagetag(new_tag)
# reading / writing / adding / deleting files in the opf manifest
def readfile(self, id):
# returns the contents of the file with manifest id (text files are utf-8 encoded)
return self._w.readfile(id)
def writefile(self, id, data):
# writes data to a currently existing file pointed to by the manifest id
self._w.writefile(id, data)
# Modified for epub3
def addfile(self, uniqueid, basename, data, mime=None, properties=None, fallback=None, overlay=None):
# creates a new file in the manifest with unique manifest id, basename, data, and mimetype
self._w.addfile(uniqueid, basename, data, mime, properties, fallback, overlay)
def deletefile(self, id):
# removes the file associated with that manifest id, removes any existing spine entries as well
self._w.deletefile(id)
# New for epub3
def set_manifest_epub3_attributes(self, id, properties=None, fallback=None, overlay=None):
# sets the epub3 manifest attrobutes for this manifest id
self._w.set_manifest_epub3_attributes(id, properties, fallback, overlay)
# reading / writing / adding / deleting other ebook files that DO NOT exist in the opf manifest
def readotherfile(self, book_href):
# returns the contents of the file pointed to by the ebook href
return self._w.readotherfile(book_href)
def writeotherfile(self, book_href, data):
# writes data to a currently existing file pointed to by the ebook href
self._w.writeotherfile(book_href, data)
def addotherfile(self, book_href, data):
# creates a new file with desired ebook href
self._w.addotherfile(book_href, data)
def deleteotherfile(self, book_href):
# removes file pointed to by the ebook href
self._w.deleteotherfile(book_href)
# iterators
def text_iter(self):
# yields manifest id, href in spine order plus any non-spine items
text_set = set([k for k, v in self._w.id_to_mime.items() if v == 'application/xhtml+xml'])
for (id, linear, properties) in self._w.spine:
if id in text_set:
text_set -= set([id])
href = self._w.id_to_href[id]
yield id, href
for id in text_set:
href = self._w.id_to_href[id]
yield id, href
def css_iter(self):
# yields manifest id, href
for id in sorted(self._w.id_to_mime):
mime = self._w.id_to_mime[id]
if mime == 'text/css':
href = self._w.id_to_href[id]
yield id, href
def image_iter(self):
# yields manifest id, href, and mimetype
for id in sorted(self._w.id_to_mime):
mime = self._w.id_to_mime[id]
if mime.startswith('image'):
href = self._w.id_to_href[id]
yield id, href, mime
def font_iter(self):
# yields manifest id, href, and mimetype
for id in sorted(self._w.id_to_mime):
mime = self._w.id_to_mime[id]
if 'font-' in mime or 'truetype' in mime or 'opentype' in mime or mime.startswith('font/'):
href = self._w.id_to_href[id]
yield id, href, mime
def manifest_iter(self):
# yields manifest id, href, and mimetype
for id in sorted(self._w.id_to_mime):
mime = self._w.id_to_mime[id]
href = self._w.id_to_href[id]
yield id, href, mime
# New for epub3
def manifest_epub3_iter(self):
# yields manifest id, href, mimetype, properties, fallback, media-overlay
for id in sorted(self._w.id_to_mime):
mime = self._w.id_to_mime[id]
href = self._w.id_to_href[id]
properties = self._w.id_to_props[id]
fallback = self._w.id_to_fall[id]
overlay = self._w.id_to_over[id]
yield id, href, mime, properties, fallback, overlay
def spine_iter(self):
# yields spine idref, linear(yes,no,None), href in spine order
for (id, linear, properties) in self._w.spine:
href = self._w.id_to_href[id]
yield id, linear, href
# New for epub3
def spine_epub3_iter(self):
# yields spine idref, linear(yes,no,None), properties, href in spine order
for (id, linear, properties) in self._w.spine:
href = self._w.id_to_href[id]
yield id, linear, properties, href
def guide_iter(self):
# yields guide reference type, title, href, and manifest id of href
for (type, title, href) in self._w.guide:
thref = href.split('#')[0]
id = self._w.href_to_id.get(thref, None)
yield type, title, href, id
# New for epub3
def bindings_epub3_iter(self):
# yields media-type handler in bindings order
for (mtype, handler) in self._w.bindings:
handler_href = self._w.id_to_href[handler]
yield mtype, handler, handler_href
def media_iter(self):
# yields manifest, title, href, and manifest id of href
for id in sorted(self._w.id_to_mime):
mime = self._w.id_to_mime[id]
if mime.startswith('audio') or mime.startswith('video'):
href = self._w.id_to_href[id]
yield id, href, mime
def other_iter(self):
# yields otherid for each file not in the manifest
for book_href in self._w.other:
yield book_href
def selected_iter(self):
# yields id type ('other' or 'manifest') and id/otherid for each file selected in the BookBrowser
for book_href in self._w.selected:
id_type = 'other'
id = book_href
if book_href in self._w.bookpath_to_id:
id_type = 'manifest'
id = self._w.bookpath_to_id[book_href]
yield id_type, id
# miscellaneous routines
# build the current opf incorporating all changes to date and return it
def get_opf(self):
return self._w.build_opf()
# create your own current copy of all ebook contents in destintation directory
def copy_book_contents_to(self, destdir):
self._w.copy_book_contents_to(destdir)
# get path to hunspell dll / library
def get_hunspell_library_path(self):
return self._w.get_hunspell_path()
# get a list of the directories that contain Sigil's hunspell dictionaries
def get_dictionary_dirs(self):
return self._w.get_dictionary_dirs()
# get status of epub file open inside of Sigil
def get_epub_is_modified(self):
return self._w.epub_isDirty
# get path to currently open epub or an inside Sigil or empty string if unsaved
def get_epub_filepath(self):
return self._w.epub_filepath
# new for Sigil 2.2.0
def font_bookpath_to_preferred_obfuscation_algorithm(self, bookpath, ow=None):
return self._w.map_font_bookpath_to_mangling_algorithm(bookpath, ow)
# functions for converting from manifest id to href, basename, mimetype etc
def href_to_id(self, href, ow=None):
return self._w.map_href_to_id(href, ow)
def id_to_mime(self, id, ow=None):
return self._w.map_id_to_mime(id, ow)
def basename_to_id(self, basename, ow=None):
return self._w.map_basename_to_id(basename, ow)
def id_to_href(self, id, ow=None):
return self._w.map_id_to_href(id, ow)
def href_to_basename(self, href, ow=None):
if href is not None:
return href.split('/')[-1]
return ow
# New for epub3
def id_to_properties(self, id, ow=None):
return self._w.map_id_to_properties(id, ow)
def id_to_fallback(self, id, ow=None):
return self._w.map_id_to_fallback(id, ow)
def id_to_overlay(self, id, ow=None):
return self._w.map_id_to_overlay(id, ow)
# New in Sigil 1.1
# ----------------
# returns "light" or "dark"
def colorMode(self):
return self._w.colorMode()
# returns color as css or javascript hex color string #xxxxxx
# acccepts the following color roles in a case insensitive manner:
# "Window", "Base", "Text", "Highlight", "HighlightedText"
def color(self, role):
return self._w.color(role)
# New in Sigil 1.0
# ----------------
# A book path (aka bookpath) is a unique relative path from the
# ebook root to a specific file in the epub. As a relative path meant
# to be used in an href or src "link", it only uses forward slashes "/"
# as path separators. Since all files exist inside the
# epub root (folder the epub was unzipped into), bookpaths will NEVER
# have or use "./" or "../" ie they are in always in canonical form
# For example under Sigil pre 1.0, all epubs were put into a standard
# structure. Under this standard structure book paths would look like
# the following:
# OEBPS/content.opf
# OEBPS/toc.ncx
# OEBPS/Text/Section0001.xhtml
# OEBPS/Images/cover.jpg
#
# and src and hrefs always looked like the following:
# from Section0001.xhtml to Section0002.xhtml: ../Text/Section0002.xhtml
# from Section0001.xhtml to cover.jpg: ../Images/cover.jpg
# from content.opf to Section0001.xhtml Text/Section0001.xhtml
# from toc.ncx to Section0001.xhtml Text/Section0001.xhtml
# Under Sigil 1.0 and later, the original epub structure can be preserved
# meaning that files like content.opf could be named package.opf, and be placed
# almost anyplace inside the epub. This is true for almost all files.
# So to uniquely identify a file, you need to know the bookpath of the OPF
# and the manifest href to the specific file, or the path from the epub
# root to the file itself (ie. its bookpath)
# so the Sigil plugin interface for Sigil 1.0 has been extended to allow
# the plugin developer to more easily work with bookpaths, create links
# between bookpaths, etc.
# we will use the terms book_href (or bookhref) interchangeably
# with bookpath with the following convention:
# - use book_href when working with "other" files outside the manifest
# - use bookpath when working with files in the opf manifest
# - use either when working with the OPF file as it is at the intersection
# returns the bookpath/book_href to the opf file
def get_opfbookpath(self):
return self._w.get_opfbookpath()
# returns the book path of the folder containing this bookpath
def get_startingdir(self, bookpath):
return self._w.get_startingdir(bookpath)
# return a bookpath for the file pointed to by the href
# from the specified bookpath starting directory
def build_bookpath(self, href, starting_dir):
return self._w.build_bookpath(href, starting_dir)
# returns the href relative path from source bookpath to target bookpath
def get_relativepath(self, from_bookpath, to_bookpath):
return self._w.get_relativepath(from_bookpath, to_bookpath)
# adds a new file to the *manifest* with the stated bookpath with the provided
# uniqueid, data, (and mediatype if specified)
def addbookpath(self, uniqueid, bookpath, data, mime=None):
return self._w.addbookpath(uniqueid, bookpath, data, mime)
# functions for converting from manifest id to bookpath and back
def bookpath_to_id(self, bookpath, ow=None):
return self._w.map_bookpath_to_id(bookpath, ow)
def id_to_bookpath(self, id, ow=None):
return self._w.map_id_to_bookpath(id, ow)
# valid groups: Text, Styles, Images, Fonts, Audio, Video, ncx, opf, Misc
# returns a sorted folder list of ebook paths for a group
def group_to_folders(self, group, ow=None):
return self._w.map_group_to_folders(group, ow)
def mediatype_to_group(self, mediatype, ow=None):
return self._w.map_mediatype_to_group(mediatype, ow)
# Newly Added to Support Plugins running in Automate Lists
def using_automate(self):
return self._w.using_automate
def automate_parameter(self):
return self._w.automate_parameter