mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Merge from trunk
This commit is contained in:
commit
4ce44843ec
@ -355,3 +355,11 @@ draw_hidden_section_indicators = True
|
||||
# large covers
|
||||
maximum_cover_size = (1200, 1600)
|
||||
|
||||
#: Where to send downloaded news
|
||||
# When automatically sending downloaded news to a connected device, calibre
|
||||
# will by default send it to the main memory. By changing this tweak, you can
|
||||
# control where it is sent. Valid values are "main", "carda", "cardb". Note
|
||||
# that if there isn't enough free space available on the location you choose,
|
||||
# the files will be sent to the location with the most free space.
|
||||
send_news_to_device_location = "main"
|
||||
|
||||
|
21
resources/recipes/evangelizo.recipe
Normal file
21
resources/recipes/evangelizo.recipe
Normal file
@ -0,0 +1,21 @@
|
||||
import re
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class Evangelizo(BasicNewsRecipe):
|
||||
title = 'Evangelizo.org'
|
||||
oldest_article = 2
|
||||
max_articles_per_feed = 30
|
||||
language = 'de'
|
||||
__author__ = 'Bobus'
|
||||
feeds = [
|
||||
('EvangleliumTagfuerTag', 'http://www.evangeliumtagfuertag.org/rss/evangelizo_rss-de.xml'),
|
||||
]
|
||||
use_embedded_content = True
|
||||
preprocess_regexps = [
|
||||
(re.compile(r'<font size="-2">([(][0-9]*[)])</font>'), r'\g<1>'),
|
||||
(re.compile(r'([\.!]\n)'), r'\g<1><br />'),
|
||||
]
|
||||
|
||||
def populate_article_metadata(self, article, soup, first):
|
||||
article.title = re.sub(r'<font size="-2">([(][0-9]*[)])</font>', r'\g<1>', article.title)
|
||||
return
|
@ -16,7 +16,7 @@ from lxml import etree
|
||||
from calibre.ebooks.chardet import xml_to_unicode
|
||||
from calibre.constants import __appname__, __version__, filesystem_encoding
|
||||
from calibre.ebooks.metadata.toc import TOC
|
||||
from calibre.ebooks.metadata import string_to_authors, MetaInformation
|
||||
from calibre.ebooks.metadata import string_to_authors, MetaInformation, check_isbn
|
||||
from calibre.ebooks.metadata.book.base import Metadata
|
||||
from calibre.utils.date import parse_date, isoformat
|
||||
from calibre.utils.localization import get_lang
|
||||
@ -863,6 +863,7 @@ class OPF(object): # {{{
|
||||
for x in self.XPath(
|
||||
'descendant::*[local-name() = "identifier" and text()]')(
|
||||
self.metadata):
|
||||
found_scheme = False
|
||||
for attr, val in x.attrib.iteritems():
|
||||
if attr.endswith('scheme'):
|
||||
typ = icu_lower(val)
|
||||
@ -870,7 +871,15 @@ class OPF(object): # {{{
|
||||
method='text').strip()
|
||||
if val and typ not in ('calibre', 'uuid'):
|
||||
identifiers[typ] = val
|
||||
found_scheme = True
|
||||
break
|
||||
if not found_scheme:
|
||||
val = etree.tostring(x, with_tail=False, encoding=unicode,
|
||||
method='text').strip()
|
||||
if val.lower().startswith('urn:isbn:'):
|
||||
val = check_isbn(val.split(':')[-1])
|
||||
if val is not None:
|
||||
identifiers['isbn'] = val
|
||||
return identifiers
|
||||
|
||||
@dynamic_property
|
||||
|
@ -322,7 +322,7 @@ class Amazon(Source):
|
||||
# }}}
|
||||
|
||||
def identify(self, log, result_queue, abort, title=None, authors=None, # {{{
|
||||
identifiers={}, timeout=20):
|
||||
identifiers={}, timeout=30):
|
||||
'''
|
||||
Note this method will retry without identifiers automatically if no
|
||||
match is found with identifiers.
|
||||
@ -436,7 +436,7 @@ if __name__ == '__main__':
|
||||
|
||||
( # An e-book ISBN not on Amazon, one of the authors is
|
||||
# unknown to Amazon, so no popup wrapper
|
||||
{'identifiers':{'isbn': '0307459671'},
|
||||
{'identifiers':{'isbn': '9780307459671'},
|
||||
'title':'Invisible Gorilla', 'authors':['Christopher Chabris']},
|
||||
[title_test('The Invisible Gorilla: And Other Ways Our Intuitions Deceive Us',
|
||||
exact=True), authors_test(['Christopher Chabris', 'Daniel Simons'])]
|
||||
|
@ -137,6 +137,16 @@ class Source(Plugin):
|
||||
'''
|
||||
Identify a book by its title/author/isbn/etc.
|
||||
|
||||
If identifiers(s) are specified and no match is found and this metadata
|
||||
source does not store all related identifiers (for example, all ISBNs
|
||||
of a book), this method should retry with just the title and author
|
||||
(assuming they were specified).
|
||||
|
||||
If this metadata source also provides covers, the URL to the cover
|
||||
should be cached so that a subsequent call to the get covers API with
|
||||
the same ISBN/special identifier does not need to get the cover URL
|
||||
again. Use the caching API for this.
|
||||
|
||||
:param log: A log object, use it to output debugging information/errors
|
||||
:param result_queue: A result Queue, results should be put into it.
|
||||
Each result is a Metadata object
|
||||
|
@ -50,7 +50,7 @@ def get_details(browser, url, timeout): # {{{
|
||||
if gc() != 403:
|
||||
raise
|
||||
# Google is throttling us, wait a little
|
||||
time.sleep(1)
|
||||
time.sleep(2)
|
||||
raw = browser.open_novisit(url, timeout=timeout).read()
|
||||
|
||||
return raw
|
||||
@ -195,7 +195,7 @@ class GoogleBooks(Source):
|
||||
ans = to_metadata(br, log, i, timeout)
|
||||
if isinstance(ans, Metadata):
|
||||
result_queue.put(ans)
|
||||
for isbn in ans.all_isbns:
|
||||
for isbn in getattr(ans, 'all_isbns', []):
|
||||
self.cache_isbn_to_identifier(isbn,
|
||||
ans.identifiers['google'])
|
||||
except:
|
||||
@ -206,7 +206,7 @@ class GoogleBooks(Source):
|
||||
break
|
||||
|
||||
def identify(self, log, result_queue, abort, title=None, authors=None, # {{{
|
||||
identifiers={}, timeout=20):
|
||||
identifiers={}, timeout=30):
|
||||
query = self.create_query(log, title=title, authors=authors,
|
||||
identifiers=identifiers)
|
||||
br = self.browser
|
||||
@ -225,6 +225,11 @@ class GoogleBooks(Source):
|
||||
log.exception('Failed to parse identify results')
|
||||
return as_unicode(e)
|
||||
|
||||
if not entries and identifiers and title and authors and \
|
||||
not abort.is_set():
|
||||
return self.identify(log, result_queue, abort, title=title,
|
||||
authors=authors, timeout=timeout)
|
||||
|
||||
# There is no point running these queries in threads as google
|
||||
# throttles requests returning 403 Forbidden errors
|
||||
self.get_all_details(br, log, entries, abort, result_queue, timeout)
|
||||
@ -235,13 +240,16 @@ class GoogleBooks(Source):
|
||||
if __name__ == '__main__':
|
||||
# To run these test use: calibre-debug -e src/calibre/ebooks/metadata/sources/google.py
|
||||
from calibre.ebooks.metadata.sources.test import (test_identify_plugin,
|
||||
title_test)
|
||||
title_test, authors_test)
|
||||
test_identify_plugin(GoogleBooks.name,
|
||||
[
|
||||
|
||||
|
||||
(
|
||||
{'identifiers':{'isbn': '0743273567'}},
|
||||
[title_test('The great gatsby', exact=True)]
|
||||
{'identifiers':{'isbn': '0743273567'}, 'title':'Great Gatsby',
|
||||
'authors':['Fitzgerald']},
|
||||
[title_test('The great gatsby', exact=True),
|
||||
authors_test(['Francis Scott Fitzgerald'])]
|
||||
),
|
||||
|
||||
#(
|
||||
|
@ -46,6 +46,16 @@ def authors_test(authors):
|
||||
|
||||
return test
|
||||
|
||||
def _test_fields(touched_fields, mi):
|
||||
for key in touched_fields:
|
||||
if key.startswith('identifier:'):
|
||||
key = key.partition(':')[-1]
|
||||
if not mi.has_identifier(key):
|
||||
return 'identifier: ' + key
|
||||
elif mi.is_null(key):
|
||||
return key
|
||||
|
||||
|
||||
def test_identify_plugin(name, tests):
|
||||
'''
|
||||
:param name: Plugin name
|
||||
@ -95,7 +105,7 @@ def test_identify_plugin(name, tests):
|
||||
prints(mi)
|
||||
prints('\n\n')
|
||||
|
||||
match_found = None
|
||||
possibles = []
|
||||
for mi in results:
|
||||
test_failed = False
|
||||
for tfunc in test_funcs:
|
||||
@ -103,26 +113,23 @@ def test_identify_plugin(name, tests):
|
||||
test_failed = True
|
||||
break
|
||||
if not test_failed:
|
||||
match_found = mi
|
||||
break
|
||||
possibles.append(mi)
|
||||
|
||||
if match_found is None:
|
||||
if not possibles:
|
||||
prints('ERROR: No results that passed all tests were found')
|
||||
prints('Log saved to', lf)
|
||||
raise SystemExit(1)
|
||||
|
||||
for key in plugin.touched_fields:
|
||||
if key.startswith('identifier:'):
|
||||
key = key.partition(':')[-1]
|
||||
if not match_found.has_identifier(key):
|
||||
prints('Failed to find identifier:', key)
|
||||
raise SystemExit(1)
|
||||
elif match_found.is_null(key):
|
||||
prints('Failed to find', key)
|
||||
good = [x for x in possibles if _test_fields(plugin.touched_fields, x) is
|
||||
None]
|
||||
if not good:
|
||||
prints('Failed to find', _test_fields(plugin.touched_fields,
|
||||
possibles[0]))
|
||||
raise SystemExit(1)
|
||||
|
||||
|
||||
prints('Average time per query', sum(times)/len(times))
|
||||
|
||||
if os.stat(lf).st_size > 10:
|
||||
prints('There were some errors, see log', lf)
|
||||
prints('There were some errors/warnings, see log', lf)
|
||||
|
||||
|
@ -229,7 +229,11 @@ def rewrite_links(root, link_repl_func, resolve_base_href=False):
|
||||
if 'style' in el.attrib:
|
||||
text = el.attrib['style']
|
||||
if _css_url_re.search(text) is not None:
|
||||
stext = parseStyle(text)
|
||||
try:
|
||||
stext = parseStyle(text)
|
||||
except:
|
||||
# Parsing errors are raised by cssutils
|
||||
continue
|
||||
for p in stext.getProperties(all=True):
|
||||
v = p.cssValue
|
||||
if v.CSS_VALUE_LIST == v.cssValueType:
|
||||
@ -846,6 +850,7 @@ class Manifest(object):
|
||||
return data
|
||||
|
||||
def _parse_xhtml(self, data):
|
||||
orig_data = data
|
||||
self.oeb.log.debug('Parsing', self.href, '...')
|
||||
# Convert to Unicode and normalize line endings
|
||||
data = self.oeb.decode(data)
|
||||
@ -923,6 +928,8 @@ class Manifest(object):
|
||||
|
||||
# Handle weird (non-HTML/fragment) files
|
||||
if barename(data.tag) != 'html':
|
||||
if barename(data.tag) == 'ncx':
|
||||
return self._parse_xml(orig_data)
|
||||
self.oeb.log.warn('File %r does not appear to be (X)HTML'%self.href)
|
||||
nroot = etree.fromstring('<html></html>')
|
||||
has_body = False
|
||||
|
290
src/calibre/ebooks/textile/functions.py
Normal file → Executable file
290
src/calibre/ebooks/textile/functions.py
Normal file → Executable file
@ -5,11 +5,13 @@ PyTextile
|
||||
A Humane Web Text Generator
|
||||
"""
|
||||
|
||||
__version__ = '2.1.4'
|
||||
|
||||
__date__ = '2009/12/04'
|
||||
# Last upstream version basis
|
||||
# __version__ = '2.1.4'
|
||||
#__date__ = '2009/12/04'
|
||||
|
||||
__copyright__ = """
|
||||
Copyright (c) 2011, Leigh Parry
|
||||
Copyright (c) 2011, John Schember <john@nachtimwald.com>
|
||||
Copyright (c) 2009, Jason Samsa, http://jsamsa.com/
|
||||
Copyright (c) 2004, Roberto A. F. De Almeida, http://dealmeida.net/
|
||||
Copyright (c) 2003, Mark Pilgrim, http://diveintomark.org/
|
||||
@ -120,6 +122,82 @@ class Textile(object):
|
||||
btag_lite = ('bq', 'bc', 'p')
|
||||
|
||||
glyph_defaults = (
|
||||
('mac_cent', '¢'),
|
||||
('mac_pound', '£'),
|
||||
('mac_yen', '¥'),
|
||||
('mac_quarter', '¼'),
|
||||
('mac_half', '½'),
|
||||
('mac_three-quarter', '¾'),
|
||||
('mac_cA-grave', 'À'),
|
||||
('mac_cA-acute', 'Á'),
|
||||
('mac_cA-circumflex', 'Â'),
|
||||
('mac_cA-tilde', 'Ã'),
|
||||
('mac_cA-diaeresis', 'Ä'),
|
||||
('mac_cA-ring', 'Å'),
|
||||
('mac_cAE', 'Æ'),
|
||||
('mac_cC-cedilla', 'Ç'),
|
||||
('mac_cE-grave', 'È'),
|
||||
('mac_cE-acute', 'É'),
|
||||
('mac_cE-circumflex', 'Ê'),
|
||||
('mac_cE-diaeresis', 'Ë'),
|
||||
('mac_cI-grave', 'Ì'),
|
||||
('mac_cI-acute', 'Í'),
|
||||
('mac_cI-circumflex', 'Î'),
|
||||
('mac_cI-diaeresis', 'Ï'),
|
||||
('mac_cEth', 'Ð'),
|
||||
('mac_cN-tilde', 'Ñ'),
|
||||
('mac_cO-grave', 'Ò'),
|
||||
('mac_cO-acute', 'Ó'),
|
||||
('mac_cO-circumflex', 'Ô'),
|
||||
('mac_cO-tilde', 'Õ'),
|
||||
('mac_cO-diaeresis', 'Ö'),
|
||||
('mac_cO-stroke', 'Ø'),
|
||||
('mac_cU-grave', 'Ù'),
|
||||
('mac_cU-acute', 'Ú'),
|
||||
('mac_cU-circumflex', 'Û'),
|
||||
('mac_cU-diaeresis', 'Ü'),
|
||||
('mac_cY-acute', 'Ý'),
|
||||
('mac_sa-grave', 'à'),
|
||||
('mac_sa-acute', 'á'),
|
||||
('mac_sa-circumflex', 'â'),
|
||||
('mac_sa-tilde', 'ã'),
|
||||
('mac_sa-diaeresis', 'ä'),
|
||||
('mac_sa-ring', 'å'),
|
||||
('mac_sae', 'æ'),
|
||||
('mac_sc-cedilla', 'ç'),
|
||||
('mac_se-grave', 'è'),
|
||||
('mac_se-acute', 'é'),
|
||||
('mac_se-circumflex', 'ê'),
|
||||
('mac_se-diaeresis', 'ë'),
|
||||
('mac_si-grave', 'ì'),
|
||||
('mac_si-acute', 'í'),
|
||||
('mac_si-circumflex', 'î'),
|
||||
('mac_si-diaeresis', 'ï'),
|
||||
('mac_sn-tilde', 'ñ'),
|
||||
('mac_so-grave', 'ò'),
|
||||
('mac_so-acute', 'ó'),
|
||||
('mac_so-circumflex', 'ô'),
|
||||
('mac_so-tilde', 'õ'),
|
||||
('mac_so-diaeresis', 'ö'),
|
||||
('mac_so-stroke', 'ø'),
|
||||
('mac_su-grave', 'ù'),
|
||||
('mac_su-acute', 'ú'),
|
||||
('mac_su-circumflex', 'û'),
|
||||
('mac_su-diaeresis', 'ü'),
|
||||
('mac_sy-acute', 'ý'),
|
||||
('mac_sy-diaeresis', 'ÿ'),
|
||||
('mac_cOE', 'Œ'),
|
||||
('mac_soe', 'œ'),
|
||||
('mac_bullet', '•'),
|
||||
('mac_franc', '₣'),
|
||||
('mac_lira', '₤'),
|
||||
('mac_rupee', '₨'),
|
||||
('mac_euro', '€'),
|
||||
('mac_spade', '♠'),
|
||||
('mac_club', '♣'),
|
||||
('mac_heart', '♥'),
|
||||
('mac_diamond', '♦'),
|
||||
('txt_dimension', '×'),
|
||||
('txt_quote_single_open', '‘'),
|
||||
('txt_quote_single_close', '’'),
|
||||
('txt_quote_double_open', '“'),
|
||||
@ -130,7 +208,6 @@ class Textile(object):
|
||||
('txt_ellipsis', '…'),
|
||||
('txt_emdash', '—'),
|
||||
('txt_endash', '–'),
|
||||
('txt_dimension', '×'),
|
||||
('txt_trademark', '™'),
|
||||
('txt_registered', '®'),
|
||||
('txt_copyright', '©'),
|
||||
@ -593,45 +670,210 @@ class Textile(object):
|
||||
'<p><cite>Cat’s Cradle</cite> by Vonnegut</p>'
|
||||
|
||||
"""
|
||||
# fix: hackish
|
||||
# fix: hackish
|
||||
text = re.sub(r'"\Z', '\" ', text)
|
||||
|
||||
glyph_search = (
|
||||
re.compile(r"(\w)\'(\w)"), # apostrophe's
|
||||
re.compile(r'(\s)\'(\d+\w?)\b(?!\')'), # back in '88
|
||||
re.compile(r'(\S)\'(?=\s|'+self.pnct+'|<|$)'), # single closing
|
||||
re.compile(r'(\d+\'?\"?)( ?)x( ?)(?=\d+)'), # dimension sign
|
||||
re.compile(r"(\w)\'(\w)"), # apostrophe's
|
||||
re.compile(r'(\s)\'(\d+\w?)\b(?!\')'), # back in '88
|
||||
re.compile(r'(\S)\'(?=\s|'+self.pnct+'|<|$)'), # single closing
|
||||
re.compile(r'\'/'), # single opening
|
||||
re.compile(r'(\S)\"(?=\s|'+self.pnct+'|<|$)'), # double closing
|
||||
re.compile(r'(\")\"'), # double closing - following another
|
||||
re.compile(r'(\S)\"(?=\s|'+self.pnct+'|<|$)'), # double closing
|
||||
re.compile(r'"'), # double opening
|
||||
re.compile(r'\b([A-Z][A-Z0-9]{2,})\b(?:[(]([^)]*)[)])'), # 3+ uppercase acronym
|
||||
re.compile(r'\b([A-Z][A-Z\'\-]+[A-Z])(?=[\s.,\)>])'), # 3+ uppercase
|
||||
re.compile(r'\b(\s{0,1})?\.{3}'), # ellipsis
|
||||
re.compile(r'\b(\s{0,1})?\.{3}'), # ellipsis
|
||||
re.compile(r'(\s?)--(\s?)'), # em dash
|
||||
re.compile(r'\s-(?:\s|$)'), # en dash
|
||||
re.compile(r'(\d+)( ?)x( ?)(?=\d+)'), # dimension sign
|
||||
re.compile(r'\b ?[([]TM[])]', re.I), # trademark
|
||||
re.compile(r'\b ?[([]R[])]', re.I), # registered
|
||||
re.compile(r'\b ?[([]C[])]', re.I), # copyright
|
||||
re.compile(r'\b( ?)[([]TM[])]', re.I), # trademark
|
||||
re.compile(r'\b( ?)[([]R[])]', re.I), # registered
|
||||
re.compile(r'\b( ?)[([]C[])]', re.I) # copyright
|
||||
)
|
||||
|
||||
glyph_replace = [x % dict(self.glyph_defaults) for x in (
|
||||
r'\1%(txt_apostrophe)s\2', # apostrophe's
|
||||
r'\1%(txt_apostrophe)s\2', # back in '88
|
||||
r'\1\2%(txt_dimension)s\3', # dimension sign
|
||||
r'\1%(txt_apostrophe)s\2', # apostrophe's
|
||||
r'\1%(txt_apostrophe)s\2', # back in '88
|
||||
r'\1%(txt_quote_single_close)s', # single closing
|
||||
r'%(txt_quote_single_open)s', # single opening
|
||||
r'\1%(txt_quote_double_close)s', # double closing
|
||||
r'%(txt_quote_double_open)s', # double opening
|
||||
r'%(txt_quote_single_open)s', # single opening
|
||||
r'\1%(txt_quote_double_close)s', # double closing - following another
|
||||
r'\1%(txt_quote_double_close)s', # double closing
|
||||
r'%(txt_quote_double_open)s', # double opening
|
||||
r'<acronym title="\2">\1</acronym>', # 3+ uppercase acronym
|
||||
r'<span class="caps">\1</span>', # 3+ uppercase
|
||||
r'\1%(txt_ellipsis)s', # ellipsis
|
||||
r'\1%(txt_ellipsis)s', # ellipsis
|
||||
r'\1%(txt_emdash)s\2', # em dash
|
||||
r' %(txt_endash)s ', # en dash
|
||||
r'\1\2%(txt_dimension)s\3', # dimension sign
|
||||
r'%(txt_trademark)s', # trademark
|
||||
r'%(txt_registered)s', # registered
|
||||
r'%(txt_copyright)s', # copyright
|
||||
r'\1%(txt_trademark)s', # trademark
|
||||
r'\1%(txt_registered)s', # registered
|
||||
r'\1%(txt_copyright)s' # copyright
|
||||
)]
|
||||
|
||||
if re.search(r'{.+?}', text):
|
||||
glyph_search += (
|
||||
re.compile(r'{(c\||\|c)}'), # cent
|
||||
re.compile(r'{(L-|-L)}'), # pound
|
||||
re.compile(r'{(Y=|=Y)}'), # yen
|
||||
re.compile(r'{\(c\)}'), # copyright
|
||||
re.compile(r'{\(r\)}'), # registered
|
||||
re.compile(r'{1/4}'), # quarter
|
||||
re.compile(r'{1/2}'), # half
|
||||
re.compile(r'{3/4}'), # three-quarter
|
||||
re.compile(r'{(A`|`A)}'), # 192;
|
||||
re.compile(r'{(A\'|\'A)}'), # 193;
|
||||
re.compile(r'{(A\^|\^A)}'), # 194;
|
||||
re.compile(r'{(A~|~A)}'), # 195;
|
||||
re.compile(r'{(A\"|\"A)}'), # 196;
|
||||
re.compile(r'{(Ao|oA)}'), # 197;
|
||||
re.compile(r'{(AE)}'), # 198;
|
||||
re.compile(r'{(C,|,C)}'), # 199;
|
||||
re.compile(r'{(E`|`E)}'), # 200;
|
||||
re.compile(r'{(E\'|\'E)}'), # 201;
|
||||
re.compile(r'{(E\^|\^E)}'), # 202;
|
||||
re.compile(r'{(E\"|\"E)}'), # 203;
|
||||
re.compile(r'{(I`|`I)}'), # 204;
|
||||
re.compile(r'{(I\'|\'I)}'), # 205;
|
||||
re.compile(r'{(I\^|\^I)}'), # 206;
|
||||
re.compile(r'{(I\"|\"I)}'), # 207;
|
||||
re.compile(r'{(D-|-D)}'), # 208;
|
||||
re.compile(r'{(N~|~N)}'), # 209;
|
||||
re.compile(r'{(O`|`O)}'), # 210;
|
||||
re.compile(r'{(O\'|\'O)}'), # 211;
|
||||
re.compile(r'{(O\^|\^O)}'), # 212;
|
||||
re.compile(r'{(O~|~O)}'), # 213;
|
||||
re.compile(r'{(O\"|\"O)}'), # 214;
|
||||
re.compile(r'{(O\/|\/O)}'), # 215;
|
||||
re.compile(r'{(U`|`U)}'), # 216;
|
||||
re.compile(r'{(U\'|\'U)}'), # 217;
|
||||
re.compile(r'{(U\^|\^U)}'), # 218;
|
||||
re.compile(r'{(U\"|\"U)}'), # 219;
|
||||
re.compile(r'{(Y\'|\'Y)}'), # 220;
|
||||
re.compile(r'{(a`|`a)}'), # a-grace
|
||||
re.compile(r'{(a\'|\'a)}'), # a-acute
|
||||
re.compile(r'{(a\^|\^a)}'), # a-circumflex
|
||||
re.compile(r'{(a~|~a)}'), # a-tilde
|
||||
re.compile(r'{(a\"|\"a)}'), # a-diaeresis
|
||||
re.compile(r'{(ao|oa)}'), # a-ring
|
||||
re.compile(r'{ae}'), # ae
|
||||
re.compile(r'{(c,|,c)}'), # c-cedilla
|
||||
re.compile(r'{(e`|`e)}'), # e-grace
|
||||
re.compile(r'{(e\'|\'e)}'), # e-acute
|
||||
re.compile(r'{(e\^|\^e)}'), # e-circumflex
|
||||
re.compile(r'{(e\"|\"e)}'), # e-diaeresis
|
||||
re.compile(r'{(i`|`i)}'), # i-grace
|
||||
re.compile(r'{(i\'|\'i)}'), # i-acute
|
||||
re.compile(r'{(i\^|\^i)}'), # i-circumflex
|
||||
re.compile(r'{(i\"|\"i)}'), # i-diaeresis
|
||||
re.compile(r'{(n~|~n)}'), # n-tilde
|
||||
re.compile(r'{(o`|`o)}'), # o-grace
|
||||
re.compile(r'{(o\'|\'o)}'), # o-acute
|
||||
re.compile(r'{(o\^|\^o)}'), # o-circumflex
|
||||
re.compile(r'{(o~|~o)}'), # o-tilde
|
||||
re.compile(r'{(o\"|\"o)}'), # o-diaeresis
|
||||
re.compile(r'{(o\/|\/o)}'), # o-stroke
|
||||
re.compile(r'{(u`|`u)}'), # u-grace
|
||||
re.compile(r'{(u\'|\'u)}'), # u-acute
|
||||
re.compile(r'{(u\^|\^u)}'), # u-circumflex
|
||||
re.compile(r'{(u\"|\"u)}'), # u-diaeresis
|
||||
re.compile(r'{(y\'|\'y)}'), # y-acute
|
||||
re.compile(r'{(y\"|\"y)}'), # y-diaeresis
|
||||
re.compile(r'{OE}'), # y-diaeresis
|
||||
re.compile(r'{oe}'), # y-diaeresis
|
||||
re.compile(r'{\*}'), # bullet
|
||||
re.compile(r'{Fr}'), # Franc
|
||||
re.compile(r'{(L=|=L)}'), # Lira
|
||||
re.compile(r'{Rs}'), # Rupee
|
||||
re.compile(r'{(C=|=C)}'), # euro
|
||||
re.compile(r'{tm}'), # euro
|
||||
re.compile(r'{spade}'), # spade
|
||||
re.compile(r'{club}'), # club
|
||||
re.compile(r'{heart}'), # heart
|
||||
re.compile(r'{diamond}') # diamond
|
||||
)
|
||||
|
||||
glyph_replace += [x % dict(self.glyph_defaults) for x in (
|
||||
r'%(mac_cent)s', # cent
|
||||
r'%(mac_pound)s', # pound
|
||||
r'%(mac_yen)s', # yen
|
||||
r'%(txt_copyright)s', # copyright
|
||||
r'%(txt_registered)s', # registered
|
||||
r'%(mac_quarter)s', # quarter
|
||||
r'%(mac_half)s', # half
|
||||
r'%(mac_three-quarter)s', # three-quarter
|
||||
r'%(mac_cA-grave)s', # 192;
|
||||
r'%(mac_cA-acute)s', # 193;
|
||||
r'%(mac_cA-circumflex)s', # 194;
|
||||
r'%(mac_cA-tilde)s', # 195;
|
||||
r'%(mac_cA-diaeresis)s', # 196;
|
||||
r'%(mac_cA-ring)s', # 197;
|
||||
r'%(mac_cAE)s', # 198;
|
||||
r'%(mac_cC-cedilla)s', # 199;
|
||||
r'%(mac_cE-grave)s', # 200;
|
||||
r'%(mac_cE-acute)s', # 201;
|
||||
r'%(mac_cE-circumflex)s', # 202;
|
||||
r'%(mac_cE-diaeresis)s', # 203;
|
||||
r'%(mac_cI-grave)s', # 204;
|
||||
r'%(mac_cI-acute)s', # 205;
|
||||
r'%(mac_cI-circumflex)s', # 206;
|
||||
r'%(mac_cI-diaeresis)s', # 207;
|
||||
r'%(mac_cEth)s', # 208;
|
||||
r'%(mac_cN-tilde)s', # 209;
|
||||
r'%(mac_cO-grave)s', # 210;
|
||||
r'%(mac_cO-acute)s', # 211;
|
||||
r'%(mac_cO-circumflex)s', # 212;
|
||||
r'%(mac_cO-tilde)s', # 213;
|
||||
r'%(mac_cO-diaeresis)s', # 214;
|
||||
r'%(mac_cO-stroke)s', # 216;
|
||||
r'%(mac_cU-grave)s', # 217;
|
||||
r'%(mac_cU-acute)s', # 218;
|
||||
r'%(mac_cU-circumflex)s', # 219;
|
||||
r'%(mac_cU-diaeresis)s', # 220;
|
||||
r'%(mac_cY-acute)s', # 221;
|
||||
r'%(mac_sa-grave)s', # 224;
|
||||
r'%(mac_sa-acute)s', # 225;
|
||||
r'%(mac_sa-circumflex)s', # 226;
|
||||
r'%(mac_sa-tilde)s', # 227;
|
||||
r'%(mac_sa-diaeresis)s', # 228;
|
||||
r'%(mac_sa-ring)s', # 229;
|
||||
r'%(mac_sae)s', # 230;
|
||||
r'%(mac_sc-cedilla)s', # 231;
|
||||
r'%(mac_se-grave)s', # 232;
|
||||
r'%(mac_se-acute)s', # 233;
|
||||
r'%(mac_se-circumflex)s', # 234;
|
||||
r'%(mac_se-diaeresis)s', # 235;
|
||||
r'%(mac_si-grave)s', # 236;
|
||||
r'%(mac_si-acute)s', # 237;
|
||||
r'%(mac_si-circumflex)s', # 238;
|
||||
r'%(mac_si-diaeresis)s', # 239;
|
||||
r'%(mac_sn-tilde)s', # 241;
|
||||
r'%(mac_so-grave)s', # 242;
|
||||
r'%(mac_so-acute)s', # 243;
|
||||
r'%(mac_so-circumflex)s', # 244;
|
||||
r'%(mac_so-tilde)s', # 245;
|
||||
r'%(mac_so-diaeresis)s', # 246;
|
||||
r'%(mac_so-stroke)s', # 248;
|
||||
r'%(mac_su-grave)s', # 249;
|
||||
r'%(mac_su-acute)s', # 250;
|
||||
r'%(mac_su-circumflex)s', # 251;
|
||||
r'%(mac_su-diaeresis)s', # 252;
|
||||
r'%(mac_sy-acute)s', # 253;
|
||||
r'%(mac_sy-diaeresis)s', # 255;
|
||||
r'%(mac_cOE)s', # 338;
|
||||
r'%(mac_soe)s', # 339;
|
||||
r'%(mac_bullet)s', # bullet
|
||||
r'%(mac_franc)s', # franc
|
||||
r'%(mac_lira)s', # lira
|
||||
r'%(mac_rupee)s', # rupee
|
||||
r'%(mac_euro)s', # euro
|
||||
r'%(txt_trademark)s', # trademark
|
||||
r'%(mac_spade)s', # spade
|
||||
r'%(mac_club)s', # club
|
||||
r'%(mac_heart)s', # heart
|
||||
r'%(mac_diamond)s' # diamond
|
||||
)]
|
||||
|
||||
result = []
|
||||
for line in re.compile(r'(<.*?>)', re.U).split(text):
|
||||
if not re.search(r'<.*>', line):
|
||||
|
@ -34,6 +34,13 @@ class ViewAction(InterfaceAction):
|
||||
self.qaction.setMenu(self.view_menu)
|
||||
ac.triggered.connect(self.view_specific_format, type=Qt.QueuedConnection)
|
||||
|
||||
self.view_menu.addSeparator()
|
||||
ac = self.create_action(spec=(_('Read a random book'), 'catalog.png',
|
||||
None, None), attr='action_pick_random')
|
||||
ac.triggered.connect(self.view_random)
|
||||
self.view_menu.addAction(ac)
|
||||
|
||||
|
||||
def location_selected(self, loc):
|
||||
enabled = loc == 'library'
|
||||
for action in list(self.view_menu.actions())[1:]:
|
||||
@ -151,6 +158,10 @@ class ViewAction(InterfaceAction):
|
||||
def view_specific_book(self, index):
|
||||
self._view_books([index])
|
||||
|
||||
def view_random(self, *args):
|
||||
self.gui.iactions['Choose Library'].pick_random()
|
||||
self._view_books([self.gui.library_view.currentIndex()])
|
||||
|
||||
def _view_books(self, rows):
|
||||
if not rows or len(rows) == 0:
|
||||
self._launch_viewer()
|
||||
|
@ -1052,11 +1052,13 @@ class DeviceMixin(object): # {{{
|
||||
except:
|
||||
pass
|
||||
total_size = self.location_manager.free[0]
|
||||
if self.location_manager.free[0] > total_size + (1024**2):
|
||||
loc = tweaks['send_news_to_device_location']
|
||||
loc_index = {"carda": 1, "cardb": 2}.get(loc, 0)
|
||||
if self.location_manager.free[loc_index] > total_size + (1024**2):
|
||||
# Send news to main memory if enough space available
|
||||
# as some devices like the Nook Color cannot handle
|
||||
# periodicals on SD cards properly
|
||||
on_card = None
|
||||
on_card = loc if loc in ('carda', 'cardb') else None
|
||||
self.upload_books(files, names, metadata,
|
||||
on_card=on_card,
|
||||
memory=[files, remove])
|
||||
|
@ -442,7 +442,7 @@ class Scheduler(QObject):
|
||||
if self.oldest > 0:
|
||||
delta = timedelta(days=self.oldest)
|
||||
try:
|
||||
ids = list(self.recipe_model.db.tags_older_than(_('News'),
|
||||
ids = list(self.db.tags_older_than(_('News'),
|
||||
delta))
|
||||
except:
|
||||
# Happens if library is being switched
|
||||
|
@ -71,7 +71,7 @@ class Customize(QFrame, Ui_Frame):
|
||||
button = getattr(self, 'button%d'%which)
|
||||
font = QFont()
|
||||
button.setFont(font)
|
||||
sequence = QKeySequence(code|int(ev.modifiers()))
|
||||
sequence = QKeySequence(code|(int(ev.modifiers())&~Qt.KeypadModifier))
|
||||
button.setText(sequence.toString())
|
||||
self.capture = 0
|
||||
setattr(self, 'shortcut%d'%which, sequence)
|
||||
@ -195,7 +195,7 @@ class Shortcuts(QAbstractListModel):
|
||||
def get_match(self, event_or_sequence, ignore=tuple()):
|
||||
q = event_or_sequence
|
||||
if isinstance(q, QKeyEvent):
|
||||
q = QKeySequence(q.key()|int(q.modifiers()))
|
||||
q = QKeySequence(q.key()|(int(q.modifiers())&~Qt.KeypadModifier))
|
||||
for key in self.order:
|
||||
if key not in ignore:
|
||||
for seq in self.get_sequences(key):
|
||||
|
@ -656,6 +656,8 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{
|
||||
pass
|
||||
time.sleep(2)
|
||||
self.hide_windows()
|
||||
# Do not report any errors that happen after the shutdown
|
||||
sys.excepthook = sys.__excepthook__
|
||||
return True
|
||||
|
||||
def run_wizard(self, *args):
|
||||
|
Loading…
x
Reference in New Issue
Block a user