def add_word(self): d = QDialog(self) d.l = l = QFormLayout(d) d.setWindowTitle(_('Add a word')) d.w = w = QLineEdit(d) w.setPlaceholderText(_('Word to add')) l.addRow(_('&Word:'), w) d.loc = loc = LanguagesEdit(parent=d) l.addRow(_('&Language:'), d.loc) loc.lang_codes = [canonicalize_lang(get_lang())] d.bb = bb = QDialogButtonBox(QDialogButtonBox.Ok|QDialogButtonBox.Cancel) bb.accepted.connect(d.accept), bb.rejected.connect(d.reject) l.addRow(bb) if d.exec_() != d.Accepted: return word = unicode(w.text()) lang = (loc.lang_codes or [canonicalize_lang(get_lang())])[0] if not word: return if (word, lang) not in self.current_dictionary.words: dictionaries.add_to_user_dictionary(self.current_dictionary.name, word, DictionaryLocale(lang, None)) dictionaries.clear_caches() self.show_current_dictionary() self.dictionaries_changed = True idx = self.find_word(word, lang) if idx > -1: self.words.scrollToItem(self.words.item(idx))
def import_words(self): d = QDialog(self) d.l = l = QFormLayout(d) d.setWindowTitle(_('Import list of words')) d.w = w = QPlainTextEdit(d) l.addRow(QLabel(_('Enter a list of words, one per line'))) l.addRow(w) d.b = b = QPushButton(_('Paste from clipboard')) l.addRow(b) b.clicked.connect(w.paste) d.la = la = QLabel(_('Words in the user dictionary must have an associated language. Choose the language below:')) la.setWordWrap(True) l.addRow(la) d.le = le = LanguagesEdit(d) lc = canonicalize_lang(get_lang()) if lc: le.lang_codes = [lc] l.addRow(_('&Language:'), le) d.bb = bb = QDialogButtonBox(QDialogButtonBox.Ok|QDialogButtonBox.Cancel) l.addRow(bb) bb.accepted.connect(d.accept), bb.rejected.connect(d.reject) if d.exec_() != d.Accepted: return lc = le.lang_codes if not lc: return error_dialog(self, _('Must specify language'), _( 'You must specify a language to import words'), show=True) words = set(filter(None, [x.strip() for x in unicode(w.toPlainText()).splitlines()])) lang = lc[0] words = {(w, lang) for w in words} - self.current_dictionary.words if dictionaries.add_to_user_dictionary(self.current_dictionary.name, words, None): dictionaries.clear_caches() self.show_current_dictionary() self.dictionaries_changed = True
def init_languages(self): self.language.blockSignals(True) self.language.clear() from calibre.utils.localization import (available_translations, get_language, get_lang, get_lc_messages_path) lang = get_lang() lang = get_lc_messages_path(lang) if lang else lang if lang is None or lang not in available_translations(): lang = 'en' def get_esc_lang(l): if l == 'en': return 'English' return get_language(l) self.language.addItem(get_esc_lang(lang), (lang)) items = [(l, get_esc_lang(l)) for l in available_translations() if l != lang] if lang != 'en': items.append(('en', get_esc_lang('en'))) items.sort(cmp=lambda x, y: cmp(x[1], y[1])) for item in items: self.language.addItem(item[1], (item[0])) self.language.blockSignals(False) prefs['language'] = str(self.language.itemData(self.language.currentIndex()) or '')
def commit_ncx_toc(container, toc, lang=None, uid=None): tocname = find_existing_ncx_toc(container) if tocname is None: item = container.generate_item('toc.ncx', id_prefix='toc') tocname = container.href_to_name(item.get('href'), base=container.opf_name) ncx_id = item.get('id') [s.set('toc', ncx_id) for s in container.opf_xpath('//opf:spine')] if not lang: lang = get_lang() for l in container.opf_xpath('//dc:language'): l = canonicalize_lang(xml2text(l).strip()) if l: lang = l lang = lang_as_iso639_1(l) or l break lang = lang_as_iso639_1(lang) or lang if not uid: uid = uuid_id() eid = container.opf.get('unique-identifier', None) if eid: m = container.opf_xpath('//*[@id="%s"]' % eid) if m: uid = xml2text(m[0]) title = _('Table of Contents') m = container.opf_xpath('//dc:title') if m: x = xml2text(m[0]).strip() title = x or title to_href = partial(container.name_to_href, base=tocname) root = create_ncx(toc, to_href, title, lang, uid) container.replace(tocname, root) container.pretty_print.add(tocname)
def get_title_sort_pat(lang=None): ans = _title_pats.get(lang, None) if ans is not None: return ans q = lang from calibre.utils.localization import canonicalize_lang, get_lang if lang is None: q = tweaks['default_language_for_title_sort'] if q is None: q = get_lang() q = canonicalize_lang(q) if q else q data = tweaks['per_language_title_sort_articles'] try: ans = data.get(q, None) except AttributeError: ans = None # invalid tweak value try: ans = frozenset(ans) if ans else frozenset(data['eng']) except: ans = frozenset((r'A\s+', r'The\s+', r'An\s+')) ans = '|'.join(ans) ans = '^(%s)'%ans try: ans = re.compile(ans, re.IGNORECASE) except: ans = re.compile(r'^(A|The|An)\s+', re.IGNORECASE) _title_pats[lang] = ans return ans
def setup_ui(self): self.l = l = QFormLayout(self) self.setLayout(l) self.title = t = QLineEdit(self) l.addRow(_('&Title:'), t) t.setFocus(Qt.OtherFocusReason) self.authors = a = QLineEdit(self) l.addRow(_('&Authors:'), a) a.setText(tprefs.get('previous_new_book_authors', '')) self.languages = la = LanguagesEdit(self) l.addRow(_('&Language:'), la) la.lang_codes = (tprefs.get('previous_new_book_lang', canonicalize_lang(get_lang())), ) bb = self.bb l.addRow(bb) bb.clear() bb.addButton(bb.Cancel) b = bb.addButton('&EPUB', bb.AcceptRole) b.clicked.connect(partial(self.set_fmt, 'epub')) b = bb.addButton('&AZW3', bb.AcceptRole) b.clicked.connect(partial(self.set_fmt, 'azw3'))
def load_translations(namespace, zfp): null = object() trans = _translations_cache.get(zfp, null) if trans is None: return if trans is null: from calibre.utils.localization import get_lang lang = get_lang() if not lang or lang == 'en': # performance optimization _translations_cache[zfp] = None return with zipfile.ZipFile(zfp) as zf: try: mo = zf.read('translations/%s.mo' % lang) except KeyError: mo = None # No translations for this language present if mo is None: _translations_cache[zfp] = None return from gettext import GNUTranslations from io import BytesIO trans = _translations_cache[zfp] = GNUTranslations(BytesIO(mo)) namespace['_'] = trans.gettext namespace['ngettext'] = trans.ngettext
def _metadata_from_opf(self, opf): from calibre.ebooks.metadata.opf2 import OPF from calibre.ebooks.oeb.transforms.metadata import meta_info_to_oeb_metadata stream = cStringIO.StringIO(etree.tostring(opf, xml_declaration=True, encoding='utf-8')) o = OPF(stream) pwm = o.primary_writing_mode if pwm: self.oeb.metadata.primary_writing_mode = pwm mi = o.to_book_metadata() if not mi.language: mi.language = get_lang().replace('_', '-') self.oeb.metadata.add('language', mi.language) if not mi.book_producer: mi.book_producer = '%(a)s (%(v)s) [http://%(a)s-ebook.com]'%\ dict(a=__appname__, v=__version__) meta_info_to_oeb_metadata(mi, self.oeb.metadata, self.logger) m = self.oeb.metadata m.add('identifier', str(uuid.uuid4()), id='uuid_id', scheme='uuid') self.oeb.uid = self.oeb.metadata.identifier[-1] if not m.title: m.add('title', self.oeb.translate(__('Unknown'))) has_aut = False for x in m.creator: if getattr(x, 'role', '').lower() in ('', 'aut'): has_aut = True break if not has_aut: m.add('creator', self.oeb.translate(__('Unknown')), role='aut')
def add_quick_start_guide(library_view, refresh_cover_browser=None): from calibre.ebooks.metadata.meta import get_metadata from calibre.ebooks.covers import calibre_cover2 from calibre.utils.zipfile import safe_replace from calibre.utils.localization import get_lang, canonicalize_lang from calibre.ptempfile import PersistentTemporaryFile l = canonicalize_lang(get_lang()) or 'eng' gprefs['quick_start_guide_added'] = True imgbuf = BytesIO(calibre_cover2(_('Quick Start Guide'), '')) try: with lopen(P('quick_start/%s.epub' % l), 'rb') as src: buf = BytesIO(src.read()) except EnvironmentError as err: if err.errno != errno.ENOENT: raise with lopen(P('quick_start/eng.epub'), 'rb') as src: buf = BytesIO(src.read()) safe_replace(buf, 'images/cover.jpg', imgbuf) buf.seek(0) mi = get_metadata(buf, 'epub') with PersistentTemporaryFile('.epub') as tmp: tmp.write(buf.getvalue()) library_view.model().add_books([tmp.name], ['epub'], [mi]) os.remove(tmp.name) library_view.model().books_added(1) if refresh_cover_browser is not None: refresh_cover_browser() if library_view.model().rowCount(None) < 3: library_view.resizeColumnsToContents()
def __init__(self, mi, source_plugin, title, authors, identifiers): same_identifier = 2 idents = mi.get_identifiers() for k, v in identifiers.iteritems(): if idents.get(k) == v: same_identifier = 1 break all_fields = 1 if source_plugin.test_fields(mi) is None else 2 exact_title = 1 if title and \ cleanup_title(title) == cleanup_title(mi.title) else 2 language = 1 if mi.language: mil = canonicalize_lang(mi.language) if mil != 'und' and mil != canonicalize_lang(get_lang()): language = 2 has_cover = 2 if ( not source_plugin.cached_cover_url_is_reliable or source_plugin.get_cached_cover_url(mi.identifiers) is None) else 1 self.base = (same_identifier, has_cover, all_fields, language, exact_title) self.comments_len = len(mi.comments.strip() if mi.comments else '') self.extra = (getattr(mi, 'source_relevance', 0), )
def _metadata_from_opf(self, opf): from calibre.ebooks.metadata.opf2 import OPF from calibre.ebooks.oeb.transforms.metadata import meta_info_to_oeb_metadata stream = io.BytesIO( etree.tostring(opf, xml_declaration=True, encoding='utf-8')) o = OPF(stream) pwm = o.primary_writing_mode if pwm: self.oeb.metadata.primary_writing_mode = pwm mi = o.to_book_metadata() if not mi.language: mi.language = get_lang().replace('_', '-') self.oeb.metadata.add('language', mi.language) if not mi.book_producer: mi.book_producer = '%(a)s (%(v)s) [http://%(a)s-ebook.com]'%\ dict(a=__appname__, v=__version__) meta_info_to_oeb_metadata(mi, self.oeb.metadata, self.logger) m = self.oeb.metadata m.add('identifier', unicode_type(uuid.uuid4()), id='uuid_id', scheme='uuid') self.oeb.uid = self.oeb.metadata.identifier[-1] if not m.title: m.add('title', self.oeb.translate(__('Unknown'))) has_aut = False for x in m.creator: if getattr(x, 'role', '').lower() in ('', 'aut'): has_aut = True break if not has_aut: m.add('creator', self.oeb.translate(__('Unknown')), role='aut')
def lang(): global _lang if _lang is None: from calibre.utils.localization import get_lang _lang = get_lang().lower() return _lang
def load_translations(namespace, zfp): null = object() trans = _translations_cache.get(zfp, null) if trans is None: return if trans is null: from calibre.utils.localization import get_lang lang = get_lang() if not lang or lang == 'en': # performance optimization _translations_cache[zfp] = None return with zipfile.ZipFile(zfp) as zf: try: mo = zf.read('translations/%s.mo' % lang) except KeyError: mo = None # No translations for this language present if mo is None: _translations_cache[zfp] = None return from gettext import GNUTranslations from io import BytesIO trans = _translations_cache[zfp] = GNUTranslations(BytesIO(mo)) namespace['_'] = trans.ugettext namespace['ngettext'] = trans.ungettext
def accept(self): with tprefs: tprefs.set('previous_new_book_authors', str(self.authors.text())) tprefs.set('previous_new_book_lang', (self.languages.lang_codes or [get_lang()])[0]) self.languages.update_recently_used() super().accept()
def __init__(self, args, force_calibre_style=False, override_program_name=None): self.file_event_hook = None if override_program_name: args = [override_program_name] + args[1:] qargs = [ i.encode('utf-8') if isinstance(i, unicode) else i for i in args ] self.pi = plugins['progress_indicator'][0] if DEBUG: self.redirect_notify = True QApplication.__init__(self, qargs) dl = QLocale(get_lang()) if unicode(dl.bcp47Name()) != u'C': QLocale.setDefault(dl) global gui_thread, qt_app gui_thread = QThread.currentThread() self._translator = None self.load_translations() qt_app = self self._file_open_paths = [] self._file_open_lock = RLock() self.setup_styles(force_calibre_style)
def add_quick_start_guide(library_view, refresh_cover_browser=None): from calibre.ebooks.metadata.meta import get_metadata from calibre.ebooks import calibre_cover from calibre.utils.zipfile import safe_replace from calibre.utils.localization import get_lang, canonicalize_lang from calibre.ptempfile import PersistentTemporaryFile l = canonicalize_lang(get_lang()) or 'eng' gprefs['quick_start_guide_added'] = True imgbuf = BytesIO(calibre_cover(_('Quick Start Guide'), '', author_size=8)) try: with open(P('quick_start/%s.epub' % l), 'rb') as src: buf = BytesIO(src.read()) except EnvironmentError as err: if err.errno != errno.ENOENT: raise with open(P('quick_start/eng.epub'), 'rb') as src: buf = BytesIO(src.read()) safe_replace(buf, 'images/cover.jpg', imgbuf) buf.seek(0) mi = get_metadata(buf, 'epub') with PersistentTemporaryFile('.epub') as tmp: tmp.write(buf.getvalue()) library_view.model().add_books([tmp.name], ['epub'], [mi]) os.remove(tmp.name) library_view.model().books_added(1) if refresh_cover_browser is not None: refresh_cover_browser() if library_view.model().rowCount(None) < 3: library_view.resizeColumnsToContents()
def init_languages(self): self.language.blockSignals(True) self.language.clear() from calibre.utils.localization import (available_translations, get_language, get_lang, get_lc_messages_path) lang = get_lang() lang = get_lc_messages_path(lang) if lang else lang if lang is None or lang not in available_translations(): lang = 'en' def get_esc_lang(l): if l == 'en': return 'English' return get_language(l) self.language.addItem(get_esc_lang(lang), (lang)) items = [(l, get_esc_lang(l)) for l in available_translations() if l != lang] if lang != 'en': items.append(('en', get_esc_lang('en'))) items.sort(cmp=lambda x, y: cmp(x[1], y[1])) for item in items: self.language.addItem(item[1], (item[0])) self.language.blockSignals(False) prefs['language'] = str( self.language.itemData(self.language.currentIndex()) or '')
def commit_toc(container, toc, lang=None, uid=None): tocname = find_existing_toc(container) if tocname is None: item = container.generate_item("toc.ncx", id_prefix="toc") tocname = container.href_to_name(item.get("href"), base=container.opf_name) if not lang: lang = get_lang() for l in container.opf_xpath("//dc:language"): l = canonicalize_lang(xml2text(l).strip()) if l: lang = l lang = lang_as_iso639_1(l) or l break lang = lang_as_iso639_1(lang) or lang if not uid: uid = uuid_id() eid = container.opf.get("unique-identifier", None) if eid: m = container.opf_xpath('//*[@id="%s"]' % eid) if m: uid = xml2text(m[0]) title = _("Table of Contents") m = container.opf_xpath("//dc:title") if m: x = xml2text(m[0]).strip() title = x or title to_href = partial(container.name_to_href, base=tocname) root = create_ncx(toc, to_href, title, lang, uid) container.replace(tocname, root) container.pretty_print.add(tocname)
def __init__(self, mi, source_plugin, title, authors, identifiers): same_identifier = 2 idents = mi.get_identifiers() for k, v in identifiers.iteritems(): if idents.get(k) == v: same_identifier = 1 break all_fields = 1 if source_plugin.test_fields(mi) is None else 2 exact_title = 1 if title and \ cleanup_title(title) == cleanup_title(mi.title) else 2 language = 1 if mi.language: mil = canonicalize_lang(mi.language) if mil != 'und' and mil != canonicalize_lang(get_lang()): language = 2 has_cover = 2 if (not source_plugin.cached_cover_url_is_reliable or source_plugin.get_cached_cover_url(mi.identifiers) is None) else 1 self.base = (same_identifier, has_cover, all_fields, language, exact_title) self.comments_len = len(mi.comments.strip() if mi.comments else '') self.extra = (getattr(mi, 'source_relevance', 0), )
def add_quick_start_guide(library_view, db_images): from calibre.ebooks.metadata.meta import get_metadata from calibre.ebooks import calibre_cover from calibre.utils.zipfile import safe_replace from calibre.utils.localization import get_lang, canonicalize_lang from calibre.ptempfile import PersistentTemporaryFile l = canonicalize_lang(get_lang()) or "eng" gprefs["quick_start_guide_added"] = True imgbuf = BytesIO(calibre_cover(_("Quick Start Guide"), "", author_size=8)) try: with open(P("quick_start/%s.epub" % l), "rb") as src: buf = BytesIO(src.read()) except EnvironmentError as err: if err.errno != errno.ENOENT: raise with open(P("quick_start/eng.epub"), "rb") as src: buf = BytesIO(src.read()) safe_replace(buf, "images/cover.jpg", imgbuf) buf.seek(0) mi = get_metadata(buf, "epub") with PersistentTemporaryFile(".epub") as tmp: tmp.write(buf.getvalue()) library_view.model().add_books([tmp.name], ["epub"], [mi]) os.remove(tmp.name) library_view.model().books_added(1) if hasattr(db_images, "reset"): db_images.reset() if library_view.model().rowCount(None) < 3: library_view.resizeColumnsToContents()
def commit_ncx_toc(container, toc, lang=None, uid=None): tocname = find_existing_ncx_toc(container) if tocname is None: item = container.generate_item('toc.ncx', id_prefix='toc') tocname = container.href_to_name(item.get('href'), base=container.opf_name) ncx_id = item.get('id') [s.set('toc', ncx_id) for s in container.opf_xpath('//opf:spine')] if not lang: lang = get_lang() for l in container.opf_xpath('//dc:language'): l = canonicalize_lang(xml2text(l).strip()) if l: lang = l lang = lang_as_iso639_1(l) or l break lang = lang_as_iso639_1(lang) or lang if not uid: uid = uuid_id() eid = container.opf.get('unique-identifier', None) if eid: m = container.opf_xpath('//*[@id="%s"]'%eid) if m: uid = xml2text(m[0]) title = _('Table of Contents') m = container.opf_xpath('//dc:title') if m: x = xml2text(m[0]).strip() title = x or title to_href = partial(container.name_to_href, base=tocname) root = create_ncx(toc, to_href, title, lang, uid) container.replace(tocname, root) container.pretty_print.add(tocname)
def _create_oebbook(self, hhcpath, basedir, opts, log, mi): import uuid from lxml import html from calibre.ebooks.conversion.plumber import create_oebbook from calibre.ebooks.oeb.base import DirContainer oeb = create_oebbook(log, None, opts, encoding=opts.input_encoding, populate=False) self.oeb = oeb metadata = oeb.metadata if mi.title: metadata.add('title', mi.title) if mi.authors: for a in mi.authors: metadata.add('creator', a, attrib={'role':'aut'}) if mi.publisher: metadata.add('publisher', mi.publisher) if mi.isbn: metadata.add('identifier', mi.isbn, attrib={'scheme':'ISBN'}) if not metadata.language: oeb.logger.warn(u'Language not specified') metadata.add('language', get_lang().replace('_', '-')) if not metadata.creator: oeb.logger.warn('Creator not specified') metadata.add('creator', _('Unknown')) if not metadata.title: oeb.logger.warn('Title not specified') metadata.add('title', _('Unknown')) bookid = str(uuid.uuid4()) metadata.add('identifier', bookid, id='uuid_id', scheme='uuid') for ident in metadata.identifier: if 'id' in ident.attrib: self.oeb.uid = metadata.identifier[0] break hhcdata = self._read_file(hhcpath) hhcroot = html.fromstring(hhcdata) chapters = self._process_nodes(hhcroot) #print "=============================" #print "Printing hhcroot" #print etree.tostring(hhcroot, pretty_print=True) #print "=============================" log.debug('Found %d section nodes' % len(chapters)) if len(chapters) > 0: path0 = chapters[0][1] subpath = os.path.dirname(path0) htmlpath = os.path.join(basedir, subpath) oeb.container = DirContainer(htmlpath, log) for chapter in chapters: title = chapter[0] basename = os.path.basename(chapter[1]) self._add_item(oeb, title, basename) oeb.container = DirContainer(htmlpath, oeb.log) return oeb
def get_locale(): global _locale if _locale is None: from calibre.utils.localization import get_lang if tweaks['locale_for_sorting']: _locale = tweaks['locale_for_sorting'] else: _locale = get_lang() return _locale
def default_lookup_website(lang): if lang == 'und': lang = get_lang() lang = lang_as_iso639_1(lang) or lang if lang == 'en': prefix = 'https://www.wordnik.com/words/' else: prefix = 'http://%s.wiktionary.org/wiki/' % lang return prefix + '{word}'
def default_lookup_website(lang): if lang == "und": lang = get_lang() lang = lang_as_iso639_1(lang) or lang if lang == "en": prefix = "https://www.wordnik.com/words/" else: prefix = "http://%s.wiktionary.org/wiki/" % lang return prefix + "{word}"
def __init__(self): self.dictionaries = {} self.word_cache = {} self.ignored_words = set() try: self.default_locale = parse_lang_code(get_lang()) except ValueError: self.default_locale = parse_lang_code('en-US') self.ui_locale = self.default_locale
def __init__(self): self.dictionaries = {} self.word_cache = {} self.ignored_words = set() try: self.default_locale = parse_lang_code(get_lang()) except ValueError: self.default_locale = parse_lang_code("en-US") self.ui_locale = self.default_locale
def __init__(self): self.remove_hyphenation = re.compile('[\u2010-]+') self.dictionaries = {} self.word_cache = {} self.ignored_words = set() try: self.default_locale = parse_lang_code(get_lang()) except ValueError: self.default_locale = parse_lang_code('en-US') self.ui_locale = self.default_locale
def __init__(self, args, force_calibre_style=False, override_program_name=None, headless=False, color_prefs=gprefs): self.file_event_hook = None if override_program_name: args = [override_program_name] + args[1:] if headless: if not args: args = sys.argv[:1] args.extend(['-platformpluginpath', sys.extensions_location, '-platform', 'headless']) qargs = [i.encode('utf-8') if isinstance(i, unicode) else i for i in args] self.pi = plugins['progress_indicator'][0] QApplication.__init__(self, qargs) self.setup_styles(force_calibre_style) f = QFont(QApplication.font()) if (f.family(), f.pointSize()) == ('Sans Serif', 9): # Hard coded Qt settings, no user preference detected f.setPointSize(10) QApplication.setFont(f) f = QFontInfo(f) self.original_font = (f.family(), f.pointSize(), f.weight(), f.italic(), 100) if not self.using_calibre_style and self.style().objectName() == 'fusion': # Since Qt is using the fusion style anyway, specialize it self.load_calibre_style() fi = gprefs['font'] if fi is not None: font = QFont(*(fi[:4])) s = gprefs.get('font_stretch', None) if s is not None: font.setStretch(s) QApplication.setFont(font) dl = QLocale(get_lang()) if unicode(dl.bcp47Name()) != u'C': QLocale.setDefault(dl) global gui_thread, qt_app gui_thread = QThread.currentThread() self._translator = None self.load_translations() qt_app = self self._file_open_paths = [] self._file_open_lock = RLock() if not isosx: # OS X uses a native color dialog that does not support custom # colors self.color_prefs = color_prefs self.read_custom_colors() self.lastWindowClosed.connect(self.save_custom_colors) if isxp: error_dialog(None, _('Windows XP not supported'), '<p>' + _( 'calibre versions newer than 2.0 do not run on Windows XP. This is' ' because the graphics toolkit calibre uses (Qt 5) crashes a lot' ' on Windows XP. We suggest you stay with <a href="%s">calibre 1.48</a>' ' which works well on Windows XP.') % 'http://download.calibre-ebook.com/1.48.0/', show=True) raise SystemExit(1)
def __init__(self): self.remove_hyphenation = re.compile('[\u2010-]+') self.negative_pat = re.compile('-[.\d+]') self.fix_punctuation_pat = re.compile(r'''[:.]''') self.dictionaries = {} self.word_cache = {} self.ignored_words = set() try: self.default_locale = parse_lang_code(get_lang()) except ValueError: self.default_locale = parse_lang_code('en-US') self.ui_locale = self.default_locale
def get_translations_data(): with zipfile.ZipFile( P('content-server/locales.zip', allow_user_override=False), 'r') as zf: names = set(zf.namelist()) lang = get_lang() if lang not in names: xlang = lang.split('_')[0].lower() if xlang in names: lang = xlang if lang in names: return zf.open(lang, 'r').read()
def __init__(self, args, force_calibre_style=False, override_program_name=None, headless=False): self.file_event_hook = None if override_program_name: args = [override_program_name] + args[1:] if headless: if not args: args = sys.argv[:1] args.extend([ '-platformpluginpath', sys.extensions_location, '-platform', 'headless' ]) qargs = [ i.encode('utf-8') if isinstance(i, unicode) else i for i in args ] self.pi = plugins['progress_indicator'][0] self.setup_styles(force_calibre_style) QApplication.__init__(self, qargs) f = QFont(QApplication.font()) if (f.family(), f.pointSize()) == ( 'Sans Serif', 9): # Hard coded Qt settings, no user preference detected f.setPointSize(10) QApplication.setFont(f) f = QFontInfo(f) self.original_font = (f.family(), f.pointSize(), f.weight(), f.italic(), 100) if not self.using_calibre_style and self.style().objectName( ) == 'fusion': # Since Qt is using the fusion style anyway, specialize it self.load_calibre_style() fi = gprefs['font'] if fi is not None: font = QFont(*(fi[:4])) s = gprefs.get('font_stretch', None) if s is not None: font.setStretch(s) QApplication.setFont(font) dl = QLocale(get_lang()) if unicode(dl.bcp47Name()) != u'C': QLocale.setDefault(dl) global gui_thread, qt_app gui_thread = QThread.currentThread() self._translator = None self.load_translations() qt_app = self self._file_open_paths = [] self._file_open_lock = RLock()
def __init__(self): self.remove_hyphenation = re.compile("[\u2010-]+") self.negative_pat = re.compile("-[.\d+]") self.fix_punctuation_pat = re.compile(r"""[:.]""") self.dictionaries = {} self.word_cache = {} self.ignored_words = set() self.added_user_words = {} try: self.default_locale = parse_lang_code(get_lang()) except ValueError: self.default_locale = parse_lang_code("en-US") self.ui_locale = self.default_locale
def localize_string(data): lang = canonicalize_lang(get_lang()) def key_matches(key): if key is None: return False base = re.split(r'[_.@]', key)[0] return canonicalize_lang(base) == lang matches = tuple(filter(key_matches, data)) if matches: return data[matches[0]] return data.get(None) or ''
def get_word_count(book_path): ''' Estimate a word count ''' from calibre.utils.localization import get_lang iterator = _open_epub_file(book_path) lang = iterator.opf.language lang = get_lang() if not lang else lang count = _get_epub_standard_word_count(iterator, lang) return count
def get_translations(): global _cached_translations if _cached_translations is None: _cached_translations = False with zipfile.ZipFile(P('content-server/locales.zip', allow_user_override=False), 'r') as zf: names = set(zf.namelist()) lang = get_lang() if lang not in names: xlang = lang.split('_')[0].lower() if xlang in names: lang = xlang if lang in names: _cached_translations = load_json_file(zf.open(lang, 'r')) return _cached_translations
def lookup(self, word): from urllib import quote word = quote(word.encode('utf-8')) lang = canonicalize_lang(self.view.current_language) or get_lang() or 'en' try: url = lookup_website(lang).format(word=word) except Exception: if not self.lookup_error_reported.get(lang): self.lookup_error_reported[lang] = True error_dialog(self, _('Failed to use dictionary'), _( 'Failed to use the custom dictionary for language: %s Falling back to default dictionary.') % lang, det_msg=traceback.format_exc(), show=True) url = default_lookup_website(lang).format(word=word) open_url(url)
def collator(): global _collator, _locale if _collator is None: if _locale is None: from calibre.utils.localization import get_lang if tweaks['locale_for_sorting']: _locale = tweaks['locale_for_sorting'] else: _locale = get_lang() try: _collator = _icu.Collator(_locale) except Exception as e: print ('Failed to load collator for locale: %r with error %r, using English' % (_locale, e)) _collator = _icu.Collator('en') return _collator
def collator(strength=None, numeric=None, ignore_alternate_chars=None, upper_first=None): global _locale if _locale is None: if tweaks['locale_for_sorting']: _locale = tweaks['locale_for_sorting'] else: from calibre.utils.localization import get_lang _locale = get_lang() key = strength, numeric, ignore_alternate_chars, upper_first try: ans = thread_local_collator_cache.cache.get(key) except AttributeError: thread_local_collator_cache.cache = {} ans = None if ans is not None: return ans if all(x is None for x in key): try: ans = _icu.Collator(_locale) except Exception as e: print( f'Failed to load collator for locale: {_locale!r} with error {e!r}, using English', file=sys.stderr) _locale = 'en' ans = _icu.Collator(_locale) else: ans = collator().clone() if strength is not None: ans.strength = strength if numeric is not None: ans.numeric = numeric if upper_first is not None: ans.upper_first = upper_first if ignore_alternate_chars is not None: try: ans.set_attribute( _icu.UCOL_ALTERNATE_HANDLING, _icu.UCOL_SHIFTED if ignore_alternate_chars else _icu.UCOL_NON_IGNORABLE) except AttributeError: pass # people running from source without latest binary thread_local_collator_cache.cache[key] = ans return ans
def __init__(self, parent=None): Base.__init__(self, parent) self.days = [QCheckBox(force_unicode(calendar.day_abbr[d]), self) for d in range(7)] for i, cb in enumerate(self.days): row = i % 2 col = i // 2 self.l.addWidget(cb, row, col, 1, 1) self.time = QTimeEdit(self) self.time.setDisplayFormat('hh:mm AP') if canonicalize_lang(get_lang()) in {'deu', 'nds'}: self.time.setDisplayFormat('HH:mm') self.hl = QHBoxLayout() self.l1 = QLabel(_('&Download after:')) self.l1.setBuddy(self.time) self.hl.addWidget(self.l1) self.hl.addWidget(self.time) self.l.addLayout(self.hl, 1, 3, 1, 1) self.initialize()
def __init__(self, parent=None): Base.__init__(self, parent) self.days = [QCheckBox(force_unicode(calendar.day_abbr[d]), self) for d in xrange(7)] for i, cb in enumerate(self.days): row = i % 2 col = i // 2 self.l.addWidget(cb, row, col, 1, 1) self.time = QTimeEdit(self) self.time.setDisplayFormat('hh:mm AP') if canonicalize_lang(get_lang()) in {'deu', 'nds'}: self.time.setDisplayFormat('HH:mm') self.hl = QHBoxLayout() self.l1 = QLabel(_('&Download after:')) self.l1.setBuddy(self.time) self.hl.addWidget(self.l1) self.hl.addWidget(self.time) self.l.addLayout(self.hl, 1, 3, 1, 1) self.initialize()
def load_translations(namespace, zfp): null = object() trans = _translations_cache.get(zfp, null) if trans is None: return if trans is null: from calibre.utils.localization import get_lang lang = get_lang() if not lang or lang == 'en': # performance optimization _translations_cache[zfp] = None return mo = get_resources(zfp, 'translations/%s.mo' % lang) if mo is None: _translations_cache[zfp] = None return from gettext import GNUTranslations from io import BytesIO trans = _translations_cache[zfp] = GNUTranslations(BytesIO(mo)) namespace['_'] = trans.gettext namespace['ngettext'] = trans.ngettext
def __init__(self, args, force_calibre_style=False, override_program_name=None): self.file_event_hook = None if override_program_name: args = [override_program_name] + args[1:] qargs = [i.encode('utf-8') if isinstance(i, unicode) else i for i in args] self.pi = plugins['progress_indicator'][0] if DEBUG: self.redirect_notify = True QApplication.__init__(self, qargs) dl = QLocale(get_lang()) if unicode(dl.bcp47Name()) != u'C': QLocale.setDefault(dl) global gui_thread, qt_app gui_thread = QThread.currentThread() self._translator = None self.load_translations() qt_app = self self._file_open_paths = [] self._file_open_lock = RLock() self.setup_styles(force_calibre_style)
def __init__(self, args, force_calibre_style=False, override_program_name=None, headless=False): self.file_event_hook = None if override_program_name: args = [override_program_name] + args[1:] if headless: if not args: args = sys.argv[:1] args.extend(['-platformpluginpath', sys.extensions_location, '-platform', 'headless']) qargs = [i.encode('utf-8') if isinstance(i, unicode) else i for i in args] self.pi = plugins['progress_indicator'][0] self.setup_styles(force_calibre_style) QApplication.__init__(self, qargs) f = QFont(QApplication.font()) if (f.family(), f.pointSize()) == ('Sans Serif', 9): # Hard coded Qt settings, no user preference detected f.setPointSize(10) QApplication.setFont(f) f = QFontInfo(f) self.original_font = (f.family(), f.pointSize(), f.weight(), f.italic(), 100) if not self.using_calibre_style and self.style().objectName() == 'fusion': # Since Qt is using the fusion style anyway, specialize it self.load_calibre_style() fi = gprefs['font'] if fi is not None: font = QFont(*(fi[:4])) s = gprefs.get('font_stretch', None) if s is not None: font.setStretch(s) QApplication.setFont(font) dl = QLocale(get_lang()) if unicode(dl.bcp47Name()) != u'C': QLocale.setDefault(dl) global gui_thread, qt_app gui_thread = QThread.currentThread() self._translator = None self.load_translations() qt_app = self self._file_open_paths = [] self._file_open_lock = RLock()
def setup_ui(self): self.l = l = QFormLayout(self) self.setLayout(l) self.title = t = QLineEdit(self) l.addRow(_('&Title:'), t) t.setFocus(Qt.OtherFocusReason) self.authors = a = QLineEdit(self) l.addRow(_('&Authors:'), a) a.setText(tprefs.get('previous_new_book_authors', '')) self.languages = la = LanguagesEdit(self) l.addRow(_('&Language:'), la) la.lang_codes = (tprefs.get('previous_new_book_lang', canonicalize_lang(get_lang())),) bb = self.bb l.addRow(bb) bb.clear() bb.addButton(bb.Cancel) b = bb.addButton('&EPUB', bb.AcceptRole) connect_lambda(b.clicked, self, lambda self: self.set_fmt('epub')) b = bb.addButton('&AZW3', bb.AcceptRole) connect_lambda(b.clicked, self, lambda self: self.set_fmt('azw3'))
def create_oebbook(self, htmlpath, basedir, opts, log, mi): import uuid from calibre.ebooks.conversion.plumber import create_oebbook from calibre.ebooks.oeb.base import (DirContainer, rewrite_links, urlnormalize, urldefrag, BINARY_MIME, OEB_STYLES, xpath, urlquote) from calibre import guess_type from calibre.ebooks.oeb.transforms.metadata import \ meta_info_to_oeb_metadata from calibre.ebooks.html.input import get_filelist from calibre.ebooks.metadata import string_to_authors from calibre.utils.localization import canonicalize_lang import css_parser, logging css_parser.log.setLevel(logging.WARN) self.OEB_STYLES = OEB_STYLES oeb = create_oebbook(log, None, opts, self, encoding=opts.input_encoding, populate=False) self.oeb = oeb metadata = oeb.metadata meta_info_to_oeb_metadata(mi, metadata, log) if not metadata.language: l = canonicalize_lang(getattr(opts, 'language', None)) if not l: oeb.logger.warn('Language not specified') l = get_lang().replace('_', '-') metadata.add('language', l) if not metadata.creator: a = getattr(opts, 'authors', None) if a: a = string_to_authors(a) if not a: oeb.logger.warn('Creator not specified') a = [self.oeb.translate(__('Unknown'))] for aut in a: metadata.add('creator', aut) if not metadata.title: oeb.logger.warn('Title not specified') metadata.add('title', self.oeb.translate(__('Unknown'))) bookid = unicode_type(uuid.uuid4()) metadata.add('identifier', bookid, id='uuid_id', scheme='uuid') for ident in metadata.identifier: if 'id' in ident.attrib: self.oeb.uid = metadata.identifier[0] break filelist = get_filelist(htmlpath, basedir, opts, log) filelist = [f for f in filelist if not f.is_binary] htmlfile_map = {} for f in filelist: path = f.path oeb.container = DirContainer(os.path.dirname(path), log, ignore_opf=True) bname = os.path.basename(path) id, href = oeb.manifest.generate(id='html', href=sanitize_file_name(bname)) htmlfile_map[path] = href item = oeb.manifest.add(id, href, 'text/html') if path == htmlpath and '%' in path: bname = urlquote(bname) item.html_input_href = bname oeb.spine.add(item, True) self.added_resources = {} self.log = log self.log('Normalizing filename cases') for path, href in htmlfile_map.items(): if not self.is_case_sensitive(path): path = path.lower() self.added_resources[path] = href self.urlnormalize, self.DirContainer = urlnormalize, DirContainer self.urldefrag = urldefrag self.guess_type, self.BINARY_MIME = guess_type, BINARY_MIME self.log('Rewriting HTML links') for f in filelist: path = f.path dpath = os.path.dirname(path) oeb.container = DirContainer(dpath, log, ignore_opf=True) href = htmlfile_map[path] try: item = oeb.manifest.hrefs[href] except KeyError: item = oeb.manifest.hrefs[urlnormalize(href)] rewrite_links(item.data, partial(self.resource_adder, base=dpath)) for item in oeb.manifest.values(): if item.media_type in self.OEB_STYLES: dpath = None for path, href in self.added_resources.items(): if href == item.href: dpath = os.path.dirname(path) break css_parser.replaceUrls( item.data, partial(self.resource_adder, base=dpath)) toc = self.oeb.toc self.oeb.auto_generated_toc = True titles = [] headers = [] for item in self.oeb.spine: if not item.linear: continue html = item.data title = ''.join(xpath(html, '/h:html/h:head/h:title/text()')) title = re.sub(r'\s+', ' ', title.strip()) if title: titles.append(title) headers.append('(unlabled)') for tag in ('h1', 'h2', 'h3', 'h4', 'h5', 'strong'): expr = '/h:html/h:body//h:%s[position()=1]/text()' header = ''.join(xpath(html, expr % tag)) header = re.sub(r'\s+', ' ', header.strip()) if header: headers[-1] = header break use = titles if len(titles) > len(set(titles)): use = headers for title, item in zip(use, self.oeb.spine): if not item.linear: continue toc.add(title, item.href) oeb.container = DirContainer(getcwd(), oeb.log, ignore_opf=True) return oeb
def run(self, path_to_output, opts, db, notification=DummyReporter()): from calibre.library.catalogs.epub_mobi_builder import CatalogBuilder from calibre.utils.logging import default_log as log # If preset specified from the cli, insert stored options from JSON file if hasattr(opts, 'preset') and opts.preset: available_presets = JSONConfig("catalog_presets") if not opts.preset in available_presets: if available_presets: print(_('Error: Preset "%s" not found.' % opts.preset)) print( _('Stored presets: %s' % ', '.join( [p for p in sorted(available_presets.keys())]))) else: print(_('Error: No stored presets.')) return 1 # Copy the relevant preset values to the opts object for item in available_presets[opts.preset]: if not item in [ 'exclusion_rules_tw', 'format', 'prefix_rules_tw' ]: setattr(opts, item, available_presets[opts.preset][item]) # Provide an unconnected device opts.connected_device = { 'is_device_connected': False, 'kind': None, 'name': None, 'save_template': None, 'serial': None, 'storage': None, } # Convert prefix_rules and exclusion_rules from JSON lists to tuples prs = [] for rule in opts.prefix_rules: prs.append(tuple(rule)) opts.prefix_rules = tuple(prs) ers = [] for rule in opts.exclusion_rules: ers.append(tuple(rule)) opts.exclusion_rules = tuple(ers) opts.log = log opts.fmt = self.fmt = path_to_output.rpartition('.')[2] # Add local options opts.creator = '%s, %s %s, %s' % (strftime('%A'), strftime('%B'), strftime('%d').lstrip('0'), strftime('%Y')) opts.creator_sort_as = '%s %s' % ('calibre', strftime('%Y-%m-%d')) opts.connected_kindle = False # Finalize output_profile op = opts.output_profile if op is None: op = 'default' if opts.connected_device['name'] and 'kindle' in opts.connected_device[ 'name'].lower(): opts.connected_kindle = True if opts.connected_device['serial'] and \ opts.connected_device['serial'][:4] in ['B004', 'B005']: op = "kindle_dx" else: op = "kindle" opts.description_clip = 380 if op.endswith( 'dx') or 'kindle' not in op else 100 opts.author_clip = 100 if op.endswith( 'dx') or 'kindle' not in op else 60 opts.output_profile = op opts.basename = "Catalog" opts.cli_environment = not hasattr(opts, 'sync') # Hard-wired to always sort descriptions by author, with series after non-series opts.sort_descriptions_by_author = True build_log = [] build_log.append( u"%s('%s'): Generating %s %sin %s environment, locale: '%s'" % (self.name, current_library_name(), self.fmt, 'for %s ' % opts.output_profile if opts.output_profile else '', 'CLI' if opts.cli_environment else 'GUI', calibre_langcode_to_name(canonicalize_lang(get_lang()), localize=False))) # If exclude_genre is blank, assume user wants all tags as genres if opts.exclude_genre.strip() == '': #opts.exclude_genre = '\[^.\]' #build_log.append(" converting empty exclude_genre to '\[^.\]'") opts.exclude_genre = 'a^' build_log.append(" converting empty exclude_genre to 'a^'") if opts.connected_device['is_device_connected'] and \ opts.connected_device['kind'] == 'device': if opts.connected_device['serial']: build_log.append(u" connected_device: '%s' #%s%s " % \ (opts.connected_device['name'], opts.connected_device['serial'][0:4], 'x' * (len(opts.connected_device['serial']) - 4))) for storage in opts.connected_device['storage']: if storage: build_log.append(u" mount point: %s" % storage) else: build_log.append(u" connected_device: '%s'" % opts.connected_device['name']) try: for storage in opts.connected_device['storage']: if storage: build_log.append(u" mount point: %s" % storage) except: build_log.append(u" (no mount points)") else: build_log.append(u" connected_device: '%s'" % opts.connected_device['name']) opts_dict = vars(opts) if opts_dict['ids']: build_log.append(" book count: %d" % len(opts_dict['ids'])) sections_list = [] if opts.generate_authors: sections_list.append('Authors') if opts.generate_titles: sections_list.append('Titles') if opts.generate_series: sections_list.append('Series') if opts.generate_genres: sections_list.append('Genres') if opts.generate_recently_added: sections_list.append('Recently Added') if opts.generate_descriptions: sections_list.append('Descriptions') if not sections_list: if opts.cli_environment: opts.log.warn( '*** No Section switches specified, enabling all Sections ***' ) opts.generate_authors = True opts.generate_titles = True opts.generate_series = True opts.generate_genres = True opts.generate_recently_added = True opts.generate_descriptions = True sections_list = [ 'Authors', 'Titles', 'Series', 'Genres', 'Recently Added', 'Descriptions' ] else: opts.log.warn( '\n*** No enabled Sections, terminating catalog generation ***' ) return [ "No Included Sections", "No enabled Sections.\nCheck E-book options tab\n'Included sections'\n" ] if opts.fmt == 'mobi' and sections_list == ['Descriptions']: warning = _( "\n*** Adding 'By Authors' Section required for MOBI output ***" ) opts.log.warn(warning) sections_list.insert(0, 'Authors') opts.generate_authors = True opts.log(u" Sections: %s" % ', '.join(sections_list)) opts.section_list = sections_list # Limit thumb_width to 1.0" - 2.0" try: if float(opts.thumb_width) < float(self.THUMB_SMALLEST): log.warning("coercing thumb_width from '%s' to '%s'" % (opts.thumb_width, self.THUMB_SMALLEST)) opts.thumb_width = self.THUMB_SMALLEST if float(opts.thumb_width) > float(self.THUMB_LARGEST): log.warning("coercing thumb_width from '%s' to '%s'" % (opts.thumb_width, self.THUMB_LARGEST)) opts.thumb_width = self.THUMB_LARGEST opts.thumb_width = "%.2f" % float(opts.thumb_width) except: log.error("coercing thumb_width from '%s' to '%s'" % (opts.thumb_width, self.THUMB_SMALLEST)) opts.thumb_width = "1.0" # eval prefix_rules if passed from command line if type(opts.prefix_rules) is not tuple: try: opts.prefix_rules = eval(opts.prefix_rules) except: log.error("malformed --prefix-rules: %s" % opts.prefix_rules) raise for rule in opts.prefix_rules: if len(rule) != 4: log.error( "incorrect number of args for --prefix-rules: %s" % repr(rule)) # eval exclusion_rules if passed from command line if type(opts.exclusion_rules) is not tuple: try: opts.exclusion_rules = eval(opts.exclusion_rules) except: log.error("malformed --exclusion-rules: %s" % opts.exclusion_rules) raise for rule in opts.exclusion_rules: if len(rule) != 3: log.error( "incorrect number of args for --exclusion-rules: %s" % repr(rule)) # Display opts keys = sorted(opts_dict.keys()) build_log.append(" opts:") for key in keys: if key in [ 'catalog_title', 'author_clip', 'connected_kindle', 'creator', 'cross_reference_authors', 'description_clip', 'exclude_book_marker', 'exclude_genre', 'exclude_tags', 'exclusion_rules', 'fmt', 'genre_source_field', 'header_note_source_field', 'merge_comments_rule', 'output_profile', 'prefix_rules', 'preset', 'read_book_marker', 'search_text', 'sort_by', 'sort_descriptions_by_author', 'sync', 'thumb_width', 'use_existing_cover', 'wishlist_tag' ]: build_log.append(" %s: %s" % (key, repr(opts_dict[key]))) if opts.verbose: log('\n'.join(line for line in build_log)) # Capture start_time opts.start_time = time.time() self.opts = opts if opts.verbose: log.info(" Begin catalog source generation (%s)" % str( datetime.timedelta(seconds=int(time.time() - opts.start_time)))) # Launch the Catalog builder catalog = CatalogBuilder(db, opts, self, report_progress=notification) try: catalog.build_sources() if opts.verbose: log.info(" Completed catalog source generation (%s)\n" % str( datetime.timedelta(seconds=int(time.time() - opts.start_time)))) except (AuthorSortMismatchException, EmptyCatalogException), e: log.error(" *** Terminated catalog generation: %s ***" % e)
def genesis(self, gui): self.gui = gui if not ismacos and not iswindows: self.label_widget_style.setVisible(False) self.opt_ui_style.setVisible(False) db = gui.library_view.model().db r = self.register try: self.icon_theme_title = json.loads(I('icon-theme.json', data=True))['name'] except Exception: self.icon_theme_title = _('Default icons') self.icon_theme.setText( _('Icon theme: <b>%s</b>') % self.icon_theme_title) self.commit_icon_theme = None self.icon_theme_button.clicked.connect(self.choose_icon_theme) self.default_author_link = DefaultAuthorLink( self.default_author_link_container) self.default_author_link.changed_signal.connect(self.changed_signal) r('gui_layout', config, restart_required=True, choices=[(_('Wide'), 'wide'), (_('Narrow'), 'narrow')]) r('hidpi', gprefs, restart_required=True, choices=[(_('Automatic'), 'auto'), (_('On'), 'on'), (_('Off'), 'off')]) if ismacos: self.opt_hidpi.setVisible(False), self.label_hidpi.setVisible( False) r('ui_style', gprefs, restart_required=True, choices=[(_('System default'), 'system'), (_('calibre style'), 'calibre')]) r('book_list_tooltips', gprefs) r('dnd_merge', gprefs) r('wrap_toolbar_text', gprefs, restart_required=True) r('show_layout_buttons', gprefs, restart_required=True) r('row_numbers_in_book_list', gprefs) r('tag_browser_old_look', gprefs) r('tag_browser_hide_empty_categories', gprefs) r('tag_browser_always_autocollapse', gprefs) r('tag_browser_show_tooltips', gprefs) r('tag_browser_allow_keyboard_focus', gprefs) r('bd_show_cover', gprefs) r('bd_overlay_cover_size', gprefs) r('cover_grid_width', gprefs) r('cover_grid_height', gprefs) r('cover_grid_cache_size_multiple', gprefs) r('cover_grid_disk_cache_size', gprefs) r('cover_grid_spacing', gprefs) r('cover_grid_show_title', gprefs) r('tag_browser_show_counts', gprefs) r('tag_browser_item_padding', gprefs) r('books_autoscroll_time', gprefs) r('qv_respects_vls', gprefs) r('qv_dclick_changes_column', gprefs) r('qv_retkey_changes_column', gprefs) r('qv_follows_column', gprefs) r('cover_flow_queue_length', config, restart_required=True) r('cover_browser_reflections', gprefs) r('cover_browser_title_template', db.prefs) fm = db.field_metadata r('cover_browser_subtitle_field', db.prefs, choices=[(_('No subtitle'), 'none')] + sorted( (fm[k].get('name'), k) for k in fm.all_field_keys() if fm[k].get('name'))) r('emblem_size', gprefs) r('emblem_position', gprefs, choices=[(_('Left'), 'left'), (_('Top'), 'top'), (_('Right'), 'right'), (_('Bottom'), 'bottom')]) r('book_list_extra_row_spacing', gprefs) r('booklist_grid', gprefs) r('book_details_comments_heading_pos', gprefs, choices=[(_('Never'), 'hide'), (_('Above text'), 'above'), (_('Beside text'), 'side')]) self.cover_browser_title_template_button.clicked.connect( self.edit_cb_title_template) self.id_links_button.clicked.connect(self.edit_id_link_rules) def get_esc_lang(l): if l == 'en': return 'English' return get_language(l) lang = get_lang() if lang is None or lang not in available_translations(): lang = 'en' items = [(l, get_esc_lang(l)) for l in available_translations() if l != lang] if lang != 'en': items.append(('en', get_esc_lang('en'))) items.sort(key=lambda x: x[1].lower()) choices = [(y, x) for x, y in items] # Default language is the autodetected one choices = [(get_language(lang), lang)] + choices r('language', prefs, choices=choices, restart_required=True) r('show_avg_rating', config) r('disable_animations', config) r('systray_icon', config, restart_required=True) r('show_splash_screen', gprefs) r('disable_tray_notification', config) r('use_roman_numerals_for_series_number', config) r('separate_cover_flow', config, restart_required=True) r('cb_fullscreen', gprefs) r('cb_preserve_aspect_ratio', gprefs) r('cb_double_click_to_activate', gprefs) choices = [(_('Off'), 'off'), (_('Small'), 'small'), (_('Medium'), 'medium'), (_('Large'), 'large')] r('toolbar_icon_size', gprefs, choices=choices) choices = [(_('If there is enough room'), 'auto'), (_('Always'), 'always'), (_('Never'), 'never')] r('toolbar_text', gprefs, choices=choices) choices = [(_('Disabled'), 'disable'), (_('By first letter'), 'first letter'), (_('Partitioned'), 'partition')] r('tags_browser_partition_method', gprefs, choices=choices) r('tags_browser_collapse_at', gprefs) r('tags_browser_collapse_fl_at', gprefs) choices = { k for k in db.field_metadata.all_field_keys() if (db.field_metadata[k]['is_category'] and (db.field_metadata[k]['datatype'] in ['text', 'series', 'enumeration']) and not db.field_metadata[k]['display'].get('is_names', False)) or (db.field_metadata[k]['datatype'] in ['composite'] and db.field_metadata[k]['display'].get('make_category', False)) } choices |= {'search'} r('tag_browser_dont_collapse', gprefs, setting=CommaSeparatedList, choices=sorted(choices, key=sort_key)) choices -= {'authors', 'publisher', 'formats', 'news', 'identifiers'} r('categories_using_hierarchy', db.prefs, setting=CommaSeparatedList, choices=sorted(choices, key=sort_key)) fm = db.field_metadata choices = sorted( ((fm[k]['name'], k) for k in fm.displayable_field_keys() if fm[k]['name']), key=lambda x: sort_key(x[0])) r('field_under_covers_in_grid', db.prefs, choices=choices) self.current_font = self.initial_font = None self.change_font_button.clicked.connect(self.change_font) self.display_model = DisplayedFields(self.gui.current_db, self.field_display_order) self.display_model.dataChanged.connect(self.changed_signal) self.field_display_order.setModel(self.display_model) connect_lambda( self.df_up_button.clicked, self, lambda self: move_field_up( self.field_display_order, self.display_model)) connect_lambda( self.df_down_button.clicked, self, lambda self: move_field_down( self.field_display_order, self.display_model)) self.qv_display_model = QVDisplayedFields(self.gui.current_db, self.qv_display_order) self.qv_display_model.dataChanged.connect(self.changed_signal) self.qv_display_order.setModel(self.qv_display_model) connect_lambda( self.qv_up_button.clicked, self, lambda self: move_field_up( self.qv_display_order, self.qv_display_model)) connect_lambda( self.qv_down_button.clicked, self, lambda self: move_field_down( self.qv_display_order, self.qv_display_model)) self.edit_rules = EditRules(self.tabWidget) self.edit_rules.changed.connect(self.changed_signal) self.tabWidget.addTab(self.edit_rules, QIcon(I('format-fill-color.png')), _('Column &coloring')) self.icon_rules = EditRules(self.tabWidget) self.icon_rules.changed.connect(self.changed_signal) self.tabWidget.addTab(self.icon_rules, QIcon(I('icon_choose.png')), _('Column &icons')) self.grid_rules = EditRules(self.emblems_tab) self.grid_rules.changed.connect(self.changed_signal) self.emblems_tab.setLayout(QVBoxLayout()) self.emblems_tab.layout().addWidget(self.grid_rules) self.tabWidget.setCurrentIndex(0) keys = [ QKeySequence('F11', QKeySequence.SequenceFormat.PortableText), QKeySequence('Ctrl+Shift+F', QKeySequence.SequenceFormat.PortableText) ] keys = [ str(x.toString(QKeySequence.SequenceFormat.NativeText)) for x in keys ] self.fs_help_msg.setText( self.fs_help_msg.text() % (QKeySequence(QKeySequence.StandardKey.FullScreen).toString( QKeySequence.SequenceFormat.NativeText))) self.size_calculated.connect(self.update_cg_cache_size, type=Qt.ConnectionType.QueuedConnection) self.tabWidget.currentChanged.connect(self.tab_changed) l = self.cg_background_box.layout() self.cg_bg_widget = w = Background(self) l.addWidget(w, 0, 0, 3, 1) self.cover_grid_color_button = b = QPushButton(_('Change &color'), self) b.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed) l.addWidget(b, 0, 1) b.clicked.connect(self.change_cover_grid_color) self.cover_grid_texture_button = b = QPushButton( _('Change &background image'), self) b.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed) l.addWidget(b, 1, 1) b.clicked.connect(self.change_cover_grid_texture) self.cover_grid_default_appearance_button = b = QPushButton( _('Restore default &appearance'), self) b.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed) l.addWidget(b, 2, 1) b.clicked.connect(self.restore_cover_grid_appearance) self.cover_grid_empty_cache.clicked.connect(self.empty_cache) self.cover_grid_open_cache.clicked.connect(self.open_cg_cache) connect_lambda(self.cover_grid_smaller_cover.clicked, self, lambda self: self.resize_cover(True)) connect_lambda(self.cover_grid_larger_cover.clicked, self, lambda self: self.resize_cover(False)) self.cover_grid_reset_size.clicked.connect(self.cg_reset_size) self.opt_cover_grid_disk_cache_size.setMinimum( self.gui.grid_view.thumbnail_cache.min_disk_cache) self.opt_cover_grid_disk_cache_size.setMaximum( self.gui.grid_view.thumbnail_cache.min_disk_cache * 100) self.opt_cover_grid_width.valueChanged.connect( self.update_aspect_ratio) self.opt_cover_grid_height.valueChanged.connect( self.update_aspect_ratio) self.opt_book_details_css.textChanged.connect(self.changed_signal) from calibre.gui2.tweak_book.editor.text import get_highlighter, get_theme self.css_highlighter = get_highlighter('css')() self.css_highlighter.apply_theme(get_theme(None)) self.css_highlighter.set_document(self.opt_book_details_css.document())
def lookup_website(lang): if lang == 'und': lang = get_lang() wm = dprefs['word_lookups'] return wm.get(lang, default_lookup_website(lang))
def __init__(self, gui, initial_panel=None): QDialog.__init__(self, gui) self.l = l = QGridLayout(self) self.setLayout(l) self.setWindowTitle(_('Preferences for Edit book')) self.setWindowIcon(QIcon(I('config.png'))) self.stacks = QStackedWidget(self) l.addWidget(self.stacks, 0, 1, 1, 1) self.categories_list = cl = QListWidget(self) cl.currentRowChanged.connect(self.stacks.setCurrentIndex) cl.clearPropertyFlags() cl.setViewMode(cl.IconMode) cl.setFlow(cl.TopToBottom) cl.setMovement(cl.Static) cl.setWrapping(False) cl.setSpacing(15) if get_lang()[:2] not in ('zh', 'ja'): cl.setWordWrap(True) l.addWidget(cl, 0, 0, 1, 1) self.bb = bb = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel) bb.accepted.connect(self.accept) bb.rejected.connect(self.reject) self.rdb = b = bb.addButton(_('Restore all &defaults'), bb.ResetRole) b.setToolTip(_('Restore defaults for all preferences')) b.clicked.connect(self.restore_all_defaults) self.rcdb = b = bb.addButton(_('Restore ¤t defaults'), bb.ResetRole) b.setToolTip(_('Restore defaults for currently displayed preferences')) b.clicked.connect(self.restore_current_defaults) self.rconfs = b = bb.addButton(_('Restore c&onfirmations'), bb.ResetRole) b.setToolTip(_('Restore all disabled confirmation prompts')) b.clicked.connect(self.restore_confirmations) l.addWidget(bb, 1, 0, 1, 2) self.resize(800, 600) geom = tprefs.get('preferences_geom', None) if geom is not None: QApplication.instance().safe_restore_geometry(self, geom) self.keyboard_panel = ShortcutConfig(self) self.keyboard_panel.initialize(gui.keyboard) self.editor_panel = EditorSettings(self) self.integration_panel = IntegrationSettings(self) self.main_window_panel = MainWindowSettings(self) self.preview_panel = PreviewSettings(self) self.toolbars_panel = ToolbarSettings(self) for name, icon, panel in [ (_('Main window'), 'page.png', 'main_window'), (_('Editor settings'), 'modified.png', 'editor'), (_('Preview settings'), 'viewer.png', 'preview'), (_('Keyboard shortcuts'), 'keyboard-prefs.png', 'keyboard'), (_('Toolbars'), 'wizard.png', 'toolbars'), (_('Integration with calibre'), 'lt.png', 'integration'), ]: i = QListWidgetItem(QIcon(I(icon)), name, cl) i.setToolTip(name) cl.addItem(i) self.stacks.addWidget(getattr(self, panel + '_panel')) cl.setCurrentRow(0) cl.item(0).setSelected(True) w, h = cl.sizeHintForColumn(0), 0 for i in range(cl.count()): h = cl.sizeHintForRow(i) cl.item(i).setSizeHint(QSize(w, h)) cl.setMaximumWidth(cl.sizeHintForColumn(0) + 35) cl.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) cl.setMinimumWidth(min(cl.maximumWidth(), cl.sizeHint().width()))
def mi(self): mi = Metadata(unicode_type(self.title.text()).strip() or _('Unknown')) mi.authors = string_to_authors(unicode_type(self.authors.text()).strip()) or [_('Unknown')] mi.languages = self.languages.lang_codes or [get_lang()] return mi
def run(self, path_to_output, opts, db, notification=DummyReporter()): from calibre.library.catalogs.epub_mobi_builder import CatalogBuilder from calibre.utils.logging import default_log as log from calibre.utils.config import JSONConfig # If preset specified from the cli, insert stored options from JSON file if hasattr(opts, 'preset') and opts.preset: available_presets = JSONConfig("catalog_presets") if opts.preset not in available_presets: if available_presets: print(_('Error: Preset "%s" not found.' % opts.preset)) print(_('Stored presets: %s' % ', '.join([p for p in sorted(available_presets.keys())]))) else: print(_('Error: No stored presets.')) return 1 # Copy the relevant preset values to the opts object for item in available_presets[opts.preset]: if item not in ['exclusion_rules_tw', 'format', 'prefix_rules_tw']: setattr(opts, item, available_presets[opts.preset][item]) # Provide an unconnected device opts.connected_device = { 'is_device_connected': False, 'kind': None, 'name': None, 'save_template': None, 'serial': None, 'storage': None, } # Convert prefix_rules and exclusion_rules from JSON lists to tuples prs = [] for rule in opts.prefix_rules: prs.append(tuple(rule)) opts.prefix_rules = tuple(prs) ers = [] for rule in opts.exclusion_rules: ers.append(tuple(rule)) opts.exclusion_rules = tuple(ers) opts.log = log opts.fmt = self.fmt = path_to_output.rpartition('.')[2] # Add local options opts.creator = '%s, %s %s, %s' % (strftime('%A'), strftime('%B'), strftime('%d').lstrip('0'), strftime('%Y')) opts.creator_sort_as = '%s %s' % ('calibre', strftime('%Y-%m-%d')) opts.connected_kindle = False # Finalize output_profile op = opts.output_profile if op is None: op = 'default' if opts.connected_device['name'] and 'kindle' in opts.connected_device['name'].lower(): opts.connected_kindle = True if opts.connected_device['serial'] and \ opts.connected_device['serial'][:4] in ['B004', 'B005']: op = "kindle_dx" else: op = "kindle" opts.description_clip = 380 if op.endswith('dx') or 'kindle' not in op else 100 opts.author_clip = 100 if op.endswith('dx') or 'kindle' not in op else 60 opts.output_profile = op opts.basename = "Catalog" opts.cli_environment = not hasattr(opts, 'sync') # Hard-wired to always sort descriptions by author, with series after non-series opts.sort_descriptions_by_author = True build_log = [] build_log.append(u"%s('%s'): Generating %s %sin %s environment, locale: '%s'" % (self.name, current_library_name(), self.fmt, 'for %s ' % opts.output_profile if opts.output_profile else '', 'CLI' if opts.cli_environment else 'GUI', calibre_langcode_to_name(canonicalize_lang(get_lang()), localize=False)) ) # If exclude_genre is blank, assume user wants all tags as genres if opts.exclude_genre.strip() == '': # opts.exclude_genre = '\[^.\]' # build_log.append(" converting empty exclude_genre to '\[^.\]'") opts.exclude_genre = 'a^' build_log.append(" converting empty exclude_genre to 'a^'") if opts.connected_device['is_device_connected'] and \ opts.connected_device['kind'] == 'device': if opts.connected_device['serial']: build_log.append(u" connected_device: '%s' #%s%s " % (opts.connected_device['name'], opts.connected_device['serial'][0:4], 'x' * (len(opts.connected_device['serial']) - 4))) for storage in opts.connected_device['storage']: if storage: build_log.append(u" mount point: %s" % storage) else: build_log.append(u" connected_device: '%s'" % opts.connected_device['name']) try: for storage in opts.connected_device['storage']: if storage: build_log.append(u" mount point: %s" % storage) except: build_log.append(u" (no mount points)") else: build_log.append(u" connected_device: '%s'" % opts.connected_device['name']) opts_dict = vars(opts) if opts_dict['ids']: build_log.append(" book count: %d" % len(opts_dict['ids'])) sections_list = [] if opts.generate_authors: sections_list.append('Authors') if opts.generate_titles: sections_list.append('Titles') if opts.generate_series: sections_list.append('Series') if opts.generate_genres: sections_list.append('Genres') if opts.generate_recently_added: sections_list.append('Recently Added') if opts.generate_descriptions: sections_list.append('Descriptions') if not sections_list: if opts.cli_environment: opts.log.warn('*** No Section switches specified, enabling all Sections ***') opts.generate_authors = True opts.generate_titles = True opts.generate_series = True opts.generate_genres = True opts.generate_recently_added = True opts.generate_descriptions = True sections_list = ['Authors', 'Titles', 'Series', 'Genres', 'Recently Added', 'Descriptions'] else: opts.log.warn('\n*** No enabled Sections, terminating catalog generation ***') return ["No Included Sections", "No enabled Sections.\nCheck E-book options tab\n'Included sections'\n"] if opts.fmt == 'mobi' and sections_list == ['Descriptions']: warning = _("\n*** Adding 'By authors' section required for MOBI output ***") opts.log.warn(warning) sections_list.insert(0, 'Authors') opts.generate_authors = True opts.log(u" Sections: %s" % ', '.join(sections_list)) opts.section_list = sections_list # Limit thumb_width to 1.0" - 2.0" try: if float(opts.thumb_width) < float(self.THUMB_SMALLEST): log.warning("coercing thumb_width from '%s' to '%s'" % (opts.thumb_width, self.THUMB_SMALLEST)) opts.thumb_width = self.THUMB_SMALLEST if float(opts.thumb_width) > float(self.THUMB_LARGEST): log.warning("coercing thumb_width from '%s' to '%s'" % (opts.thumb_width, self.THUMB_LARGEST)) opts.thumb_width = self.THUMB_LARGEST opts.thumb_width = "%.2f" % float(opts.thumb_width) except: log.error("coercing thumb_width from '%s' to '%s'" % (opts.thumb_width, self.THUMB_SMALLEST)) opts.thumb_width = "1.0" # eval prefix_rules if passed from command line if type(opts.prefix_rules) is not tuple: try: opts.prefix_rules = eval(opts.prefix_rules) except: log.error("malformed --prefix-rules: %s" % opts.prefix_rules) raise for rule in opts.prefix_rules: if len(rule) != 4: log.error("incorrect number of args for --prefix-rules: %s" % repr(rule)) # eval exclusion_rules if passed from command line if type(opts.exclusion_rules) is not tuple: try: opts.exclusion_rules = eval(opts.exclusion_rules) except: log.error("malformed --exclusion-rules: %s" % opts.exclusion_rules) raise for rule in opts.exclusion_rules: if len(rule) != 3: log.error("incorrect number of args for --exclusion-rules: %s" % repr(rule)) # Display opts keys = sorted(opts_dict.keys()) build_log.append(" opts:") for key in keys: if key in ['catalog_title', 'author_clip', 'connected_kindle', 'creator', 'cross_reference_authors', 'description_clip', 'exclude_book_marker', 'exclude_genre', 'exclude_tags', 'exclusion_rules', 'fmt', 'genre_source_field', 'header_note_source_field', 'merge_comments_rule', 'output_profile', 'prefix_rules', 'preset', 'read_book_marker', 'search_text', 'sort_by', 'sort_descriptions_by_author', 'sync', 'thumb_width', 'use_existing_cover', 'wishlist_tag']: build_log.append(" %s: %s" % (key, repr(opts_dict[key]))) if opts.verbose: log('\n'.join(line for line in build_log)) # Capture start_time opts.start_time = time.time() self.opts = opts if opts.verbose: log.info(" Begin catalog source generation (%s)" % str(datetime.timedelta(seconds=int(time.time() - opts.start_time)))) # Launch the Catalog builder catalog = CatalogBuilder(db, opts, self, report_progress=notification) try: catalog.build_sources() if opts.verbose: log.info(" Completed catalog source generation (%s)\n" % str(datetime.timedelta(seconds=int(time.time() - opts.start_time)))) except (AuthorSortMismatchException, EmptyCatalogException) as e: log.error(" *** Terminated catalog generation: %s ***" % e) except: log.error(" unhandled exception in catalog generator") raise else: recommendations = [] recommendations.append(('remove_fake_margins', False, OptionRecommendation.HIGH)) recommendations.append(('comments', '', OptionRecommendation.HIGH)) """ >>> Use to debug generated catalog code before pipeline conversion <<< """ GENERATE_DEBUG_EPUB = False if GENERATE_DEBUG_EPUB: catalog_debug_path = os.path.join(os.path.expanduser('~'), 'Desktop', 'Catalog debug') setattr(opts, 'debug_pipeline', os.path.expanduser(catalog_debug_path)) dp = getattr(opts, 'debug_pipeline', None) if dp is not None: recommendations.append(('debug_pipeline', dp, OptionRecommendation.HIGH)) if opts.output_profile and opts.output_profile.startswith("kindle"): recommendations.append(('output_profile', opts.output_profile, OptionRecommendation.HIGH)) recommendations.append(('book_producer', opts.output_profile, OptionRecommendation.HIGH)) if opts.fmt == 'mobi': recommendations.append(('no_inline_toc', True, OptionRecommendation.HIGH)) recommendations.append(('verbose', 2, OptionRecommendation.HIGH)) # Use existing cover or generate new cover cpath = None existing_cover = False try: search_text = 'title:"%s" author:%s' % ( opts.catalog_title.replace('"', '\\"'), 'calibre') matches = db.search(search_text, return_matches=True, sort_results=False) if matches: cpath = db.cover(matches[0], index_is_id=True, as_path=True) if cpath and os.path.exists(cpath): existing_cover = True except: pass if self.opts.use_existing_cover and not existing_cover: log.warning("no existing catalog cover found") if self.opts.use_existing_cover and existing_cover: recommendations.append(('cover', cpath, OptionRecommendation.HIGH)) log.info("using existing catalog cover") else: from calibre.ebooks.covers import calibre_cover2 log.info("replacing catalog cover") new_cover_path = PersistentTemporaryFile(suffix='.jpg') new_cover = calibre_cover2(opts.catalog_title, 'calibre') new_cover_path.write(new_cover) new_cover_path.close() recommendations.append(('cover', new_cover_path.name, OptionRecommendation.HIGH)) # Run ebook-convert from calibre.ebooks.conversion.plumber import Plumber plumber = Plumber(os.path.join(catalog.catalog_path, opts.basename + '.opf'), path_to_output, log, report_progress=notification, abort_after_input_dump=False) plumber.merge_ui_recommendations(recommendations) plumber.run() try: os.remove(cpath) except: pass if GENERATE_DEBUG_EPUB: from calibre.ebooks.epub import initialize_container from calibre.ebooks.tweak import zip_rebuilder from calibre.utils.zipfile import ZipFile input_path = os.path.join(catalog_debug_path, 'input') epub_shell = os.path.join(catalog_debug_path, 'epub_shell.zip') initialize_container(epub_shell, opf_name='content.opf') with ZipFile(epub_shell, 'r') as zf: zf.extractall(path=input_path) os.remove(epub_shell) zip_rebuilder(input_path, os.path.join(catalog_debug_path, 'input.epub')) if opts.verbose: log.info(" Catalog creation complete (%s)\n" % str(datetime.timedelta(seconds=int(time.time() - opts.start_time)))) # returns to gui2.actions.catalog:catalog_generated() return catalog.error