Exemple #1
0
    def run(self, opts):
        from calibre.utils.serialize import msgpack_dumps
        scripts = {}
        for x in ['console']:
            for name in basenames[x]:
                if name in ('calibre-complete', 'calibre_postinstall'):
                    continue
                scripts[name] = x

        dest = self.j(self.RESOURCES, 'scripts.calibre_msgpack')
        if self.newer(dest, self.j(self.SRC, 'calibre', 'linux.py')):
            self.info('\tCreating ' + self.b(dest))
            with open(dest, 'wb') as f:
                f.write(msgpack_dumps(scripts))

        recipe_icon_dir = self.a(
            self.j(self.RESOURCES, '..', 'recipes', 'icons'))
        dest = os.path.splitext(dest)[0] + '.zip'
        files = glob.glob(self.j(recipe_icon_dir, '*.png'))
        if self.newer(dest, files):
            self.info('\tCreating builtin_recipes.zip')
            with zipfile.ZipFile(dest, 'w', zipfile.ZIP_STORED) as zf:
                for n in sorted(files, key=self.b):
                    with open(n, 'rb') as f:
                        zf.writestr(self.b(n), f.read())

        dest = self.j(self.RESOURCES, 'ebook-convert-complete.calibre_msgpack')
        files = []
        for x in os.walk(self.j(self.SRC, 'calibre')):
            for f in x[-1]:
                if f.endswith('.py'):
                    files.append(self.j(x[0], f))
        if self.newer(dest, files):
            self.info('\tCreating ' + self.b(dest))
            complete = {}
            from calibre.ebooks.conversion.plumber import supported_input_formats
            complete['input_fmts'] = set(supported_input_formats())
            from calibre.customize.ui import available_output_formats
            complete['output'] = set(available_output_formats())
            from calibre.ebooks.conversion.cli import create_option_parser
            from calibre.utils.logging import Log
            log = Log()
            # log.outputs = []
            for inf in supported_input_formats():
                if inf in ('zip', 'rar', 'oebzip'):
                    continue
                for ouf in available_output_formats():
                    of = ouf if ouf == 'oeb' else 'dummy.' + ouf
                    p = create_option_parser(('ec', 'dummy1.' + inf, of, '-h'),
                                             log)[0]
                    complete[(inf, ouf)] = [
                        x + ' ' for x in get_opts_from_parser(p)
                    ]

            with open(dest, 'wb') as f:
                f.write(msgpack_dumps(only_unicode_recursive(complete)))
Exemple #2
0
 def convert_ebooks_to_format(self, book_ids, to_fmt):
     from calibre.customize.ui import available_output_formats
     to_fmt = to_fmt.upper()
     if to_fmt.lower() not in available_output_formats():
         return error_dialog(self.gui, _('Cannot convert'), _(
             'Conversion to the {} format is not supported').format(to_fmt), show=True)
     self.do_convert(book_ids, output_fmt=to_fmt, auto_conversion=True)
Exemple #3
0
    def send_multiple_by_mail(self, recipients, delete_from_library):
        ids = set(self.library_view.model().id(r) for r in self.library_view.selectionModel().selectedRows())
        if not ids:
            return
        db = self.current_db
        db_fmt_map = {book_id: set((db.formats(book_id, index_is_id=True) or "").upper().split(",")) for book_id in ids}
        ofmts = {x.upper() for x in available_output_formats()}
        ifmts = {x.upper() for x in available_input_formats()}
        bad_recipients = {}
        auto_convert_map = defaultdict(list)

        for to, fmts, subject in recipients:
            rfmts = set(fmts)
            ok_ids = {book_id for book_id, bfmts in db_fmt_map.iteritems() if bfmts.intersection(rfmts)}
            convert_ids = ids - ok_ids
            self.send_by_mail(to, fmts, delete_from_library, subject=subject, send_ids=ok_ids, do_auto_convert=False)
            if not rfmts.intersection(ofmts):
                bad_recipients[to] = (convert_ids, True)
                continue
            outfmt = tuple(f for f in fmts if f in ofmts)[0]
            ok_ids = {book_id for book_id in convert_ids if db_fmt_map[book_id].intersection(ifmts)}
            bad_ids = convert_ids - ok_ids
            if bad_ids:
                bad_recipients[to] = (bad_ids, False)
            if ok_ids:
                auto_convert_map[outfmt].append((to, subject, ok_ids))

        if auto_convert_map:
            titles = {book_id for x in auto_convert_map.itervalues() for data in x for book_id in data[2]}
            titles = {db.title(book_id, index_is_id=True) for book_id in titles}
            if self.auto_convert_question(
                _("Auto convert the following books before sending via email?"), list(titles)
            ):
                for ofmt, data in auto_convert_map.iteritems():
                    ids = {bid for x in data for bid in x[2]}
                    data = [(to, subject) for to, subject, x in data]
                    self.iactions["Convert Books"].auto_convert_multiple_mail(ids, data, ofmt, delete_from_library)

        if bad_recipients:
            det_msg = []
            titles = {book_id for x in bad_recipients.itervalues() for book_id in x[0]}
            titles = {book_id: db.title(book_id, index_is_id=True) for book_id in titles}
            for to, (ids, nooutput) in bad_recipients.iteritems():
                msg = (
                    _("This recipient has no valid formats defined")
                    if nooutput
                    else _("These books have no suitable input formats for conversion")
                )
                det_msg.append("%s - %s" % (to, msg))
                det_msg.extend("\t" + titles[bid] for bid in ids)
                det_msg.append("\n")
            warning_dialog(
                self,
                _("Could not send"),
                _("Could not send books to some recipients. Click Show Details for more information"),
                det_msg="\n".join(det_msg),
                show=True,
            )
Exemple #4
0
def get_output_formats(preferred_output_format):
    all_formats = {x.upper() for x in available_output_formats()}
    all_formats.discard('OEB')
    pfo = preferred_output_format.upper() if preferred_output_format else ''
    restrict = tweaks['restrict_output_formats']
    if restrict:
        fmts = [x.upper() for x in restrict]
        if pfo and pfo not in fmts and pfo in all_formats:
            fmts.append(pfo)
    else:
        fmts = list(sorted(all_formats,
                key=lambda x:{'EPUB':'!A', 'MOBI':'!B'}.get(x.upper(), x)))
    return fmts
Exemple #5
0
def get_output_formats(preferred_output_format):
    all_formats = {x.upper() for x in available_output_formats()}
    all_formats.discard('OEB')
    pfo = preferred_output_format.upper() if preferred_output_format else ''
    restrict = tweaks['restrict_output_formats']
    if restrict:
        fmts = [x.upper() for x in restrict]
        if pfo and pfo not in fmts and pfo in all_formats:
            fmts.append(pfo)
    else:
        fmts = list(sorted(all_formats,
            key=lambda x:{'EPUB':'!A', 'AZW3':'!B', 'MOBI':'!C'}.get(x.upper(), x)))
    return fmts
Exemple #6
0
 def setup_output_formats(self, db, preferred_output_format):
     if preferred_output_format:
         preferred_output_format = preferred_output_format.lower()
     output_formats = sorted(available_output_formats(),
             key=lambda x:{'EPUB':'!A', 'MOBI':'!B'}.get(x.upper(), x))
     output_formats.remove('oeb')
     preferred_output_format = preferred_output_format if \
         preferred_output_format and preferred_output_format \
         in output_formats else sort_formats_by_preference(output_formats,
                 prefs['output_format'])[0]
     self.output_formats.addItems(list(map(QString, [x.upper() for x in
         output_formats])))
     self.output_formats.setCurrentIndex(output_formats.index(preferred_output_format))
Exemple #7
0
    def send_multiple_by_mail(self, recipients, delete_from_library):
        ids = set(self.library_view.model().id(r) for r in self.library_view.selectionModel().selectedRows())
        if not ids:
            return
        db = self.current_db
        db_fmt_map = {book_id:set((db.formats(book_id, index_is_id=True) or '').upper().split(',')) for book_id in ids}
        ofmts = {x.upper() for x in available_output_formats()}
        ifmts = {x.upper() for x in available_input_formats()}
        bad_recipients = {}
        auto_convert_map = defaultdict(list)

        for to, fmts, subject in recipients:
            rfmts = set(fmts)
            ok_ids = {book_id for book_id, bfmts in db_fmt_map.iteritems() if bfmts.intersection(rfmts)}
            convert_ids = ids - ok_ids
            self.send_by_mail(to, fmts, delete_from_library, subject=subject, send_ids=ok_ids, do_auto_convert=False)
            if not rfmts.intersection(ofmts):
                bad_recipients[to] = (convert_ids, True)
                continue
            outfmt = tuple(f for f in fmts if f in ofmts)[0]
            ok_ids = {book_id for book_id in convert_ids if db_fmt_map[book_id].intersection(ifmts)}
            bad_ids = convert_ids - ok_ids
            if bad_ids:
                bad_recipients[to] = (bad_ids, False)
            if ok_ids:
                auto_convert_map[outfmt].append((to, subject, ok_ids))

        if auto_convert_map:
            titles = {book_id for x in auto_convert_map.itervalues() for data in x for book_id in data[2]}
            titles = {db.title(book_id, index_is_id=True) for book_id in titles}
            if self.auto_convert_question(
                _('Auto convert the following books before sending via email?'), list(titles)):
                for ofmt, data in auto_convert_map.iteritems():
                    ids = {bid for x in data for bid in x[2]}
                    data = [(to, subject) for to, subject, x in data]
                    self.iactions['Convert Books'].auto_convert_multiple_mail(ids, data, ofmt, delete_from_library)

        if bad_recipients:
            det_msg = []
            titles = {book_id for x in bad_recipients.itervalues() for book_id in x[0]}
            titles = {book_id:db.title(book_id, index_is_id=True) for book_id in titles}
            for to, (ids, nooutput) in bad_recipients.iteritems():
                msg = _('This recipient has no valid formats defined') if nooutput else \
                        _('These books have no suitable input formats for conversion')
                det_msg.append('%s - %s' % (to, msg))
                det_msg.extend('\t' + titles[bid] for bid in ids)
                det_msg.append('\n')
            warning_dialog(self, _('Could not send'),
                           _('Could not send books to some recipients. Click Show Details for more information'),
                           det_msg='\n'.join(det_msg), show=True)
Exemple #8
0
    def genesis(self, gui):
        self.gui = gui
        db = gui.library_view.model().db

        r = self.register
        choices = [(_('Low'), 'low'), (_('Normal'), 'normal'), (_('High'),
            'high')] if iswindows else \
                    [(_('Normal'), 'normal'), (_('Low'), 'low'), (_('Very low'),
                        'high')]
        r('worker_process_priority', prefs, choices=choices)

        r('network_timeout', prefs)

        r('new_version_notification', config)
        r('upload_news_to_device', config)
        r('delete_news_from_library_on_upload', config)

        output_formats = sorted(available_output_formats())
        output_formats.remove('oeb')
        choices = [(x.upper(), x) for x in output_formats]
        r('output_format', prefs, choices=choices, setting=OutputFormatSetting)

        restrictions = sorted(db.prefs['virtual_libraries'], key=sort_key)
        choices = [('', '')] + [(x, x) for x in restrictions]
        # check that the virtual library still exists
        vls = db.prefs['virtual_lib_on_startup']
        if vls and vls not in restrictions:
            db.prefs['virtual_lib_on_startup'] = ''
        r('virtual_lib_on_startup', db.prefs, choices=choices)
        self.reset_confirmation_button.clicked.connect(
            self.reset_confirmation_dialogs)

        self.input_up_button.clicked.connect(self.up_input)
        self.input_down_button.clicked.connect(self.down_input)
        self.opt_input_order.dropEvent = partial(input_order_drop_event, self)
        for signal in ('Activated', 'Changed', 'DoubleClicked', 'Clicked'):
            signal = getattr(self.opt_internally_viewed_formats,
                             'item' + signal)
            signal.connect(self.internally_viewed_formats_changed)

        r('bools_are_tristate', db.prefs, restart_required=True)
        r('numeric_collation', prefs, restart_required=True)
        r = self.register
        choices = [(_('Default'), 'default'), (_('Compact Metadata'), 'alt1'),
                   (_('All on 1 tab'), 'alt2')]
        r('edit_metadata_single_layout', gprefs, choices=choices)
Exemple #9
0
 def setup_output_formats(self, db, preferred_output_format):
     if preferred_output_format:
         preferred_output_format = preferred_output_format.lower()
     output_formats = sorted(available_output_formats(),
                             key=lambda x: {
                                 'EPUB': '!A',
                                 'MOBI': '!B'
                             }.get(x.upper(), x))
     output_formats.remove('oeb')
     preferred_output_format = preferred_output_format if \
         preferred_output_format and preferred_output_format \
         in output_formats else sort_formats_by_preference(output_formats,
                 prefs['output_format'])[0]
     self.output_formats.addItems(
         list(map(QString, [x.upper() for x in output_formats])))
     self.output_formats.setCurrentIndex(
         output_formats.index(preferred_output_format))
Exemple #10
0
    def genesis(self, gui):
        self.gui = gui
        db = gui.library_view.model().db

        r = self.register
        choices = [(_('Low'), 'low'), (_('Normal'), 'normal'), (_('High'),
            'high')] if iswindows else \
                    [(_('Normal'), 'normal'), (_('Low'), 'low'), (_('Very low'),
                        'high')]
        r('worker_process_priority', prefs, choices=choices)

        r('network_timeout', prefs)

        r('new_version_notification', config)
        r('upload_news_to_device', config)
        r('delete_news_from_library_on_upload', config)

        output_formats = list(sorted(available_output_formats()))
        output_formats.remove('oeb')
        choices = [(x.upper(), x) for x in output_formats]
        r('output_format', prefs, choices=choices, setting=OutputFormatSetting)

        restrictions = sorted(db.prefs['virtual_libraries'], key=sort_key)
        choices = [('', '')] + [(x, x) for x in restrictions]
        # check that the virtual library still exists
        vls = db.prefs['virtual_lib_on_startup']
        if vls and vls not in restrictions:
            db.prefs['virtual_lib_on_startup'] = ''
        r('virtual_lib_on_startup', db.prefs, choices=choices)
        self.reset_confirmation_button.clicked.connect(self.reset_confirmation_dialogs)

        self.input_up_button.clicked.connect(self.up_input)
        self.input_down_button.clicked.connect(self.down_input)
        for signal in ('Activated', 'Changed', 'DoubleClicked', 'Clicked'):
            signal = getattr(self.opt_internally_viewed_formats, 'item'+signal)
            signal.connect(self.internally_viewed_formats_changed)

        r('bools_are_tristate', db.prefs, restart_required=True)
        r = self.register
        choices = [(_('Default'), 'default'), (_('Compact Metadata'), 'alt1'),
                   (_('All on 1 tab'), 'alt2')]
        r('edit_metadata_single_layout', gprefs, choices=choices)
Exemple #11
0
    def do_ebook_convert(self, f):
        from calibre.ebooks.conversion.plumber import supported_input_formats
        from calibre.web.feeds.recipes.collection import get_builtin_recipe_titles
        from calibre.customize.ui import available_output_formats
        from calibre.ebooks.conversion.cli import create_option_parser, group_titles
        from calibre.utils.logging import DevNull
        input_fmts = set(supported_input_formats())
        output_fmts = set(available_output_formats())
        iexts = {x.upper() for x in input_fmts}.union(input_fmts)
        oexts = {x.upper() for x in output_fmts}.union(output_fmts)
        w = lambda x: f.write(x if isinstance(x, bytes) else x.encode('utf-8'))
        # Arg 1
        w('\n_ebc_input_args() {')
        w('\n  local extras; extras=(')
        w('\n    {-h,--help}":Show Help"')
        w('\n    "--version:Show program version"')
        w('\n    "--list-recipes:List builtin recipe names"')
        for recipe in sorted(set(get_builtin_recipe_titles())):
            recipe = recipe.replace(':', '\\:').replace('"', '\\"')
            w(u'\n    "%s.recipe"'%(recipe))
        w('\n  ); _describe -t recipes "ebook-convert builtin recipes" extras')
        w('\n  _files -g "%s"'%' '.join(('*.%s'%x for x in iexts)))
        w('\n}\n')

        # Arg 2
        w('\n_ebc_output_args() {')
        w('\n  local extras; extras=(')
        for x in output_fmts:
            w('\n    ".{0}:Convert to a .{0} file with the same name as the input file"'.format(x))
        w('\n  ); _describe -t output "ebook-convert output" extras')
        w('\n  _files -g "%s"'%' '.join(('*.%s'%x for x in oexts)))
        w('\n  _path_files -/')
        w('\n}\n')

        log = DevNull()

        def get_parser(input_fmt='epub', output_fmt=None):
            of = ('dummy2.'+output_fmt) if output_fmt else 'dummy'
            return create_option_parser(('ec', 'dummy1.'+input_fmt, of, '-h'), log)[0]

        # Common options
        input_group, output_group = group_titles()
        p = get_parser()
        opts = p.option_list
        for group in p.option_groups:
            if group.title not in {input_group, output_group}:
                opts += group.option_list
        opts.append(p.get_option('--pretty-print'))
        opts.append(p.get_option('--input-encoding'))
        opts = '\\\n  '.join(tuple(
            self.get_options(opts, file_map={'--search-replace':()})))
        w('\n_ebc_common_opts() {')
        w('\n  _arguments -s \\\n  ' + opts)
        w('\n}\n')

        # Input/Output format options
        for fmts, group_title, func in (
            (input_fmts, input_group, '_ebc_input_opts_%s'),
            (output_fmts, output_group, '_ebc_output_opts_%s'),
        ):
            for fmt in fmts:
                is_input = group_title == input_group
                if is_input and fmt in {'rar', 'zip', 'oebzip'}:
                    continue
                p = (get_parser(input_fmt=fmt) if is_input
                     else get_parser(output_fmt=fmt))
                opts = None
                for group in p.option_groups:
                    if group.title == group_title:
                        opts = [o for o in group.option_list if
                                '--pretty-print' not in o._long_opts and
                                '--input-encoding' not in o._long_opts]
                if not opts:
                    continue
                opts = '\\\n  '.join(tuple(self.get_options(opts)))
                w('\n%s() {'%(func%fmt))
                w('\n  _arguments -s \\\n  ' + opts)
                w('\n}\n')

        w('\n_ebook_convert() {')
        w('\n  local iarg oarg context state_descr state line\n  typeset -A opt_args\n  local ret=1')
        w("\n  _arguments '1: :_ebc_input_args' '*::ebook-convert output:->args' && ret=0")
        w("\n  case $state in \n  (args)")
        w('\n    iarg=${line[1]##*.}; ')
        w("\n    _arguments '1: :_ebc_output_args' '*::ebook-convert options:->args' && ret=0")
        w("\n     case $state in \n    (args)")

        w('\n      oarg=${line[1]##*.}')
        w('\n      iarg="_ebc_input_opts_${(L)iarg}"; oarg="_ebc_output_opts_${(L)oarg}"')
        w('\n      _call_function - $iarg; _call_function - $oarg; _ebc_common_opts; ret=0')
        w('\n    ;;\n    esac')

        w("\n  ;;\n  esac\n  return ret")
        w('\n}\n')
    def send_by_mail(self,
                     to,
                     fmts,
                     delete_from_library,
                     subject='',
                     send_ids=None,
                     do_auto_convert=True,
                     specific_format=None):
        ids = [
            self.library_view.model().id(r)
            for r in self.library_view.selectionModel().selectedRows()
        ] if send_ids is None else send_ids
        if not ids or len(ids) == 0:
            return

        files, _auto_ids = self.library_view.model(
        ).get_preferred_formats_from_ids(
            ids,
            fmts,
            set_metadata=True,
            specific_format=specific_format,
            exclude_auto=do_auto_convert,
            use_plugboard=plugboard_email_value,
            plugboard_formats=plugboard_email_formats)
        if do_auto_convert:
            nids = list(set(ids).difference(_auto_ids))
            ids = [i for i in ids if i in nids]
        else:
            _auto_ids = []

        full_metadata = self.library_view.model().metadata_for(ids,
                                                               get_cover=False)

        bad, remove_ids, jobnames = [], [], []
        texts, subjects, attachments, attachment_names = [], [], [], []
        for f, mi, id in zip(files, full_metadata, ids):
            t = mi.title
            if not t:
                t = _('Unknown')
            if f is None:
                bad.append(t)
            else:
                remove_ids.append(id)
                jobnames.append(t)
                attachments.append(f)
                if not subject:
                    subjects.append(_('E-book:') + ' ' + t)
                else:
                    components = get_components(subject, mi, id)
                    if not components:
                        components = [mi.title]
                    subjects.append(os.path.join(*components))
                a = authors_to_string(mi.authors if mi.authors else \
                        [_('Unknown')])
                texts.append(_('Attached, you will find the e-book') + \
                        '\n\n' + t + '\n\t' + _('by') + ' ' + a + '\n\n' + \
                        _('in the %s format.') %
                        os.path.splitext(f)[1][1:].upper())
                prefix = ascii_filename(t + ' - ' + a)
                if not isinstance(prefix, unicode):
                    prefix = prefix.decode(preferred_encoding, 'replace')
                attachment_names.append(prefix + os.path.splitext(f)[1])
        remove = remove_ids if delete_from_library else []

        to_s = list(repeat(to, len(attachments)))
        if attachments:
            send_mails(jobnames,
                       Dispatcher(partial(self.email_sent,
                                          remove=remove)), attachments, to_s,
                       subjects, texts, attachment_names, self.job_manager)
            self.status_bar.show_message(
                _('Sending email to') + ' ' + to, 3000)

        auto = []
        if _auto_ids != []:
            for id in _auto_ids:
                if specific_format == None:
                    dbfmts = self.library_view.model().db.formats(
                        id, index_is_id=True)
                    formats = [
                        f.lower()
                        for f in (dbfmts.split(',') if dbfmts else [])
                    ]
                    if list(
                            set(formats).intersection(
                                available_input_formats())) != [] and list(
                                    set(fmts).intersection(
                                        available_output_formats())) != []:
                        auto.append(id)
                    else:
                        bad.append(self.library_view.model().db.title(
                            id, index_is_id=True))
                else:
                    if specific_format in list(
                            set(fmts).intersection(
                                set(available_output_formats()))):
                        auto.append(id)
                    else:
                        bad.append(self.library_view.model().db.title(
                            id, index_is_id=True))

        if auto != []:
            format = specific_format if specific_format in list(
                set(fmts).intersection(set(
                    available_output_formats()))) else None
            if not format:
                for fmt in fmts:
                    if fmt in list(
                            set(fmts).intersection(
                                set(available_output_formats()))):
                        format = fmt
                        break
            if format is None:
                bad += auto
            else:
                autos = [
                    self.library_view.model().db.title(id, index_is_id=True)
                    for id in auto
                ]
                if self.auto_convert_question(
                        _('Auto convert the following books before sending via '
                          'email?'), autos):
                    self.iactions['Convert Books'].auto_convert_mail(
                        to, fmts, delete_from_library, auto, format, subject)

        if bad:
            bad = '\n'.join('%s' % (i, ) for i in bad)
            d = warning_dialog(
                self, _('No suitable formats'),
                _('Could not email the following books '
                  'as no suitable formats were found:'), bad)
            d.exec_()
Exemple #13
0
    def do_ebook_convert(self, f):
        from calibre.ebooks.conversion.plumber import supported_input_formats
        from calibre.web.feeds.recipes.collection import get_builtin_recipe_titles
        from calibre.customize.ui import available_output_formats
        from calibre.ebooks.conversion.cli import create_option_parser, group_titles
        from calibre.utils.logging import DevNull
        input_fmts = set(supported_input_formats())
        output_fmts = set(available_output_formats())
        iexts = {x.upper() for x in input_fmts}.union(input_fmts)
        oexts = {x.upper() for x in output_fmts}.union(output_fmts)
        w = polyglot_write(f)
        # Arg 1
        w('\n_ebc_input_args() {')
        w('\n  local extras; extras=(')
        w('\n    {-h,--help}":Show Help"')
        w('\n    "--version:Show program version"')
        w('\n    "--list-recipes:List builtin recipe names"')
        for recipe in sorted(set(get_builtin_recipe_titles())):
            recipe = recipe.replace(':', '\\:').replace('"', '\\"')
            w(u'\n    "%s.recipe"' % (recipe))
        w('\n  ); _describe -t recipes "ebook-convert builtin recipes" extras')
        w('\n  _files -g "%s"' % ' '.join(('*.%s' % x for x in iexts)))
        w('\n}\n')

        # Arg 2
        w('\n_ebc_output_args() {')
        w('\n  local extras; extras=(')
        for x in output_fmts:
            w('\n    ".{0}:Convert to a .{0} file with the same name as the input file"'
              .format(x))
        w('\n  ); _describe -t output "ebook-convert output" extras')
        w('\n  _files -g "%s"' % ' '.join(('*.%s' % x for x in oexts)))
        w('\n  _path_files -/')
        w('\n}\n')

        log = DevNull()

        def get_parser(input_fmt='epub', output_fmt=None):
            of = ('dummy2.' + output_fmt) if output_fmt else 'dummy'
            return create_option_parser(
                ('ec', 'dummy1.' + input_fmt, of, '-h'), log)[0]

        # Common options
        input_group, output_group = group_titles()
        p = get_parser()
        opts = p.option_list
        for group in p.option_groups:
            if group.title not in {input_group, output_group}:
                opts += group.option_list
        opts.append(p.get_option('--pretty-print'))
        opts.append(p.get_option('--input-encoding'))
        opts = '\\\n  '.join(
            tuple(self.get_options(opts, file_map={'--search-replace': ()})))
        w('\n_ebc_common_opts() {')
        w('\n  _arguments -s \\\n  ' + opts)
        w('\n}\n')

        # Input/Output format options
        for fmts, group_title, func in (
            (input_fmts, input_group, '_ebc_input_opts_%s'),
            (output_fmts, output_group, '_ebc_output_opts_%s'),
        ):
            for fmt in fmts:
                is_input = group_title == input_group
                if is_input and fmt in {'rar', 'zip', 'oebzip'}:
                    continue
                p = (get_parser(input_fmt=fmt) if is_input else get_parser(
                    output_fmt=fmt))
                opts = None
                for group in p.option_groups:
                    if group.title == group_title:
                        opts = [
                            o for o in group.option_list
                            if '--pretty-print' not in o._long_opts
                            and '--input-encoding' not in o._long_opts
                        ]
                if not opts:
                    continue
                opts = '\\\n  '.join(tuple(sorted(self.get_options(opts))))
                w('\n%s() {' % (func % fmt))
                w('\n  _arguments -s \\\n  ' + opts)
                w('\n}\n')

        w('\n_ebook_convert() {')
        w('\n  local iarg oarg context state_descr state line\n  typeset -A opt_args\n  local ret=1'
          )
        w("\n  _arguments '1: :_ebc_input_args' '*::ebook-convert output:->args' && ret=0"
          )
        w("\n  case $state in \n  (args)")
        w('\n    iarg=${line[1]##*.}; ')
        w("\n    _arguments '1: :_ebc_output_args' '*::ebook-convert options:->args' && ret=0"
          )
        w("\n     case $state in \n    (args)")

        w('\n      oarg=${line[1]##*.}')
        w('\n      iarg="_ebc_input_opts_${(L)iarg}"; oarg="_ebc_output_opts_${(L)oarg}"'
          )
        w('\n      _call_function - $iarg; _call_function - $oarg; _ebc_common_opts; ret=0'
          )
        w('\n    ;;\n    esac')

        w("\n  ;;\n  esac\n  return ret")
        w('\n}\n')
Exemple #14
0
    def send_by_mail(
        self, to, fmts, delete_from_library, subject="", send_ids=None, do_auto_convert=True, specific_format=None
    ):
        ids = (
            [self.library_view.model().id(r) for r in self.library_view.selectionModel().selectedRows()]
            if send_ids is None
            else send_ids
        )
        if not ids or len(ids) == 0:
            return

        files, _auto_ids = self.library_view.model().get_preferred_formats_from_ids(
            ids,
            fmts,
            set_metadata=True,
            specific_format=specific_format,
            exclude_auto=do_auto_convert,
            use_plugboard=plugboard_email_value,
            plugboard_formats=plugboard_email_formats,
        )
        if do_auto_convert:
            nids = list(set(ids).difference(_auto_ids))
            ids = [i for i in ids if i in nids]
        else:
            _auto_ids = []

        full_metadata = self.library_view.model().metadata_for(ids, get_cover=False)

        bad, remove_ids, jobnames = [], [], []
        texts, subjects, attachments, attachment_names = [], [], [], []
        for f, mi, id in zip(files, full_metadata, ids):
            t = mi.title
            if not t:
                t = _("Unknown")
            if f is None:
                bad.append(t)
            else:
                remove_ids.append(id)
                jobnames.append(t)
                attachments.append(f)
                if not subject:
                    subjects.append(_("E-book:") + " " + t)
                else:
                    components = get_components(subject, mi, id)
                    if not components:
                        components = [mi.title]
                    subjects.append(os.path.join(*components))
                a = authors_to_string(mi.authors if mi.authors else [_("Unknown")])
                texts.append(
                    _("Attached, you will find the e-book")
                    + "\n\n"
                    + t
                    + "\n\t"
                    + _("by")
                    + " "
                    + a
                    + "\n\n"
                    + _("in the %s format.") % os.path.splitext(f)[1][1:].upper()
                )
                if mi.comments and gprefs["add_comments_to_email"]:
                    from calibre.utils.html2text import html2text

                    texts[-1] += "\n\n" + _("About this book:") + "\n\n" + textwrap.fill(html2text(mi.comments))
                prefix = ascii_filename(t + " - " + a)
                if not isinstance(prefix, unicode):
                    prefix = prefix.decode(preferred_encoding, "replace")
                attachment_names.append(prefix + os.path.splitext(f)[1])
        remove = remove_ids if delete_from_library else []

        to_s = list(repeat(to, len(attachments)))
        if attachments:
            send_mails(
                jobnames,
                Dispatcher(partial(self.email_sent, remove=remove)),
                attachments,
                to_s,
                subjects,
                texts,
                attachment_names,
                self.job_manager,
            )
            self.status_bar.show_message(_("Sending email to") + " " + to, 3000)

        auto = []
        if _auto_ids != []:
            for id in _auto_ids:
                if specific_format is None:
                    dbfmts = self.library_view.model().db.formats(id, index_is_id=True)
                    formats = [f.lower() for f in (dbfmts.split(",") if dbfmts else [])]
                    if (
                        list(set(formats).intersection(available_input_formats())) != []
                        and list(set(fmts).intersection(available_output_formats())) != []
                    ):
                        auto.append(id)
                    else:
                        bad.append(self.library_view.model().db.title(id, index_is_id=True))
                else:
                    if specific_format in list(set(fmts).intersection(set(available_output_formats()))):
                        auto.append(id)
                    else:
                        bad.append(self.library_view.model().db.title(id, index_is_id=True))

        if auto != []:
            format = (
                specific_format
                if specific_format in list(set(fmts).intersection(set(available_output_formats())))
                else None
            )
            if not format:
                for fmt in fmts:
                    if fmt in list(set(fmts).intersection(set(available_output_formats()))):
                        format = fmt
                        break
            if format is None:
                bad += auto
            else:
                autos = [self.library_view.model().db.title(id, index_is_id=True) for id in auto]
                if self.auto_convert_question(
                    _("Auto convert the following books to %s before sending via " "email?") % format.upper(), autos
                ):
                    self.iactions["Convert Books"].auto_convert_mail(
                        to, fmts, delete_from_library, auto, format, subject
                    )

        if bad:
            bad = "\n".join("%s" % (i,) for i in bad)
            d = warning_dialog(
                self,
                _("No suitable formats"),
                _("Could not email the following books " "as no suitable formats were found:"),
                bad,
            )
            d.exec_()
Exemple #15
0
    def run(self, opts):
        from calibre.utils.serialize import msgpack_dumps
        scripts = {}
        for x in ('console', 'gui'):
            for name in basenames[x]:
                if name in ('calibre-complete', 'calibre_postinstall'):
                    continue
                scripts[name] = x

        dest = self.j(self.RESOURCES, 'scripts.calibre_msgpack')
        if self.newer(dest, self.j(self.SRC, 'calibre', 'linux.py')):
            self.info('\tCreating ' + os.path.basename(dest))
            with open(dest, 'wb') as f:
                f.write(msgpack_dumps(scripts))

        from calibre.web.feeds.recipes.collection import \
                serialize_builtin_recipes, iterate_over_builtin_recipe_files

        files = [x[1] for x in iterate_over_builtin_recipe_files()]

        dest = self.j(self.RESOURCES, 'builtin_recipes.xml')
        if self.newer(dest, files):
            self.info('\tCreating builtin_recipes.xml')
            xml = serialize_builtin_recipes()
            with open(dest, 'wb') as f:
                f.write(xml)

        recipe_icon_dir = self.a(self.j(self.RESOURCES, '..', 'recipes',
            'icons'))
        dest = os.path.splitext(dest)[0] + '.zip'
        files += glob.glob(self.j(recipe_icon_dir, '*.png'))
        if self.newer(dest, files):
            self.info('\tCreating builtin_recipes.zip')
            with zipfile.ZipFile(dest, 'w', zipfile.ZIP_STORED) as zf:
                for n in sorted(files, key=self.b):
                    with open(n, 'rb') as f:
                        zf.writestr(os.path.basename(n), f.read())

        dest = self.j(self.RESOURCES, 'ebook-convert-complete.calibre_msgpack')
        files = []
        for x in os.walk(self.j(self.SRC, 'calibre')):
            for f in x[-1]:
                if f.endswith('.py'):
                    files.append(self.j(x[0], f))
        if self.newer(dest, files):
            self.info('\tCreating ebook-convert-complete.pickle')
            complete = {}
            from calibre.ebooks.conversion.plumber import supported_input_formats
            complete['input_fmts'] = set(supported_input_formats())
            from calibre.web.feeds.recipes.collection import get_builtin_recipe_titles
            complete['input_recipes'] = [t+'.recipe ' for t in
                    get_builtin_recipe_titles()]
            from calibre.customize.ui import available_output_formats
            complete['output'] = set(available_output_formats())
            from calibre.ebooks.conversion.cli import create_option_parser
            from calibre.utils.logging import Log
            log = Log()
            # log.outputs = []
            for inf in supported_input_formats():
                if inf in ('zip', 'rar', 'oebzip'):
                    continue
                for ouf in available_output_formats():
                    of = ouf if ouf == 'oeb' else 'dummy.'+ouf
                    p = create_option_parser(('ec', 'dummy1.'+inf, of, '-h'),
                            log)[0]
                    complete[(inf, ouf)] = [x+' 'for x in
                            get_opts_from_parser(p)]

            with open(dest, 'wb') as f:
                f.write(msgpack_dumps(complete))

        self.info('\tCreating template-functions.json')
        dest = self.j(self.RESOURCES, 'template-functions.json')
        function_dict = {}
        import inspect
        from calibre.utils.formatter_functions import formatter_functions
        for obj in formatter_functions().get_builtins().values():
            eval_func = inspect.getmembers(obj,
                    lambda x: inspect.ismethod(x) and x.__name__ == 'evaluate')
            try:
                lines = [l[4:] for l in inspect.getsourcelines(eval_func[0][1])[0]]
            except:
                continue
            lines = ''.join(lines)
            function_dict[obj.name] = lines
        import json
        json.dump(function_dict, open(dest, 'wb'), indent=4)

        self.info('\tCreating editor-functions.json')
        dest = self.j(self.RESOURCES, 'editor-functions.json')
        function_dict = {}
        from calibre.gui2.tweak_book.function_replace import builtin_functions
        for func in builtin_functions():
            try:
                src = ''.join(inspect.getsourcelines(func)[0][1:])
            except Exception:
                continue
            src = src.replace('def ' + func.func_name, 'def replace')
            imports = ['from %s import %s' % (x.__module__, x.__name__) for x in func.imports]
            if imports:
                src = '\n'.join(imports) + '\n\n' + src
            function_dict[func.name] = src
        json.dump(function_dict, open(dest, 'wb'), indent=4)
        self.info('\tCreating user-manual-translation-stats.json')
        d = {}
        for lc, stats in iteritems(json.load(open(self.j(self.d(self.SRC), 'manual', 'locale', 'completed.json')))):
            total = sum(itervalues(stats))
            d[lc] = stats['translated'] / float(total)
        json.dump(d, open(self.j(self.RESOURCES, 'user-manual-translation-stats.json'), 'wb'), indent=4)
Exemple #16
0
    def send_by_mail(self, to, fmts, delete_from_library, subject='', send_ids=None,
            do_auto_convert=True, specific_format=None):
        ids = [self.library_view.model().id(r) for r in self.library_view.selectionModel().selectedRows()] if send_ids is None else send_ids
        if not ids or len(ids) == 0:
            return

        files, _auto_ids = self.library_view.model().get_preferred_formats_from_ids(ids,
                                    fmts, set_metadata=True,
                                    specific_format=specific_format,
                                    exclude_auto=do_auto_convert,
                                    use_plugboard=plugboard_email_value,
                                    plugboard_formats=plugboard_email_formats)
        if do_auto_convert:
            nids = list(set(ids).difference(_auto_ids))
            ids = [i for i in ids if i in nids]
        else:
            _auto_ids = []

        full_metadata = self.library_view.model().metadata_for(ids,
                get_cover=False)

        bad, remove_ids, jobnames = [], [], []
        texts, subjects, attachments, attachment_names = [], [], [], []
        for f, mi, id in zip(files, full_metadata, ids):
            t = mi.title
            if not t:
                t = _('Unknown')
            if f is None:
                bad.append(t)
            else:
                remove_ids.append(id)
                jobnames.append(t)
                attachments.append(f)
                if not subject:
                    subjects.append(_('E-book:')+ ' '+t)
                else:
                    components = get_components(subject, mi, id)
                    if not components:
                        components = [mi.title]
                    subjects.append(os.path.join(*components))
                a = authors_to_string(mi.authors if mi.authors else
                        [_('Unknown')])
                texts.append(_('Attached, you will find the e-book') +
                        '\n\n' + t + '\n\t' + _('by') + ' ' + a + '\n\n' +
                        _('in the %s format.') %
                        os.path.splitext(f)[1][1:].upper())
                prefix = ascii_filename(t+' - '+a)
                if not isinstance(prefix, unicode):
                    prefix = prefix.decode(preferred_encoding, 'replace')
                attachment_names.append(prefix + os.path.splitext(f)[1])
        remove = remove_ids if delete_from_library else []

        to_s = list(repeat(to, len(attachments)))
        if attachments:
            send_mails(jobnames,
                    Dispatcher(partial(self.email_sent, remove=remove)),
                    attachments, to_s, subjects, texts, attachment_names,
                    self.job_manager)
            self.status_bar.show_message(_('Sending email to')+' '+to, 3000)

        auto = []
        if _auto_ids != []:
            for id in _auto_ids:
                if specific_format is None:
                    dbfmts = self.library_view.model().db.formats(id, index_is_id=True)
                    formats = [f.lower() for f in (dbfmts.split(',') if dbfmts else
                        [])]
                    if list(set(formats).intersection(available_input_formats())) != [] and list(set(fmts).intersection(available_output_formats())) != []:
                        auto.append(id)
                    else:
                        bad.append(self.library_view.model().db.title(id, index_is_id=True))
                else:
                    if specific_format in list(set(fmts).intersection(set(available_output_formats()))):
                        auto.append(id)
                    else:
                        bad.append(self.library_view.model().db.title(id, index_is_id=True))

        if auto != []:
            format = specific_format if specific_format in list(set(fmts).intersection(set(available_output_formats()))) else None
            if not format:
                for fmt in fmts:
                    if fmt in list(set(fmts).intersection(set(available_output_formats()))):
                        format = fmt
                        break
            if format is None:
                bad += auto
            else:
                autos = [self.library_view.model().db.title(id, index_is_id=True) for id in auto]
                if self.auto_convert_question(
                    _('Auto convert the following books to %s before sending via '
                        'email?') % format.upper(), autos):
                    self.iactions['Convert Books'].auto_convert_mail(to, fmts, delete_from_library, auto, format, subject)

        if bad:
            bad = '\n'.join('%s'%(i,) for i in bad)
            d = warning_dialog(self, _('No suitable formats'),
                _('Could not email the following books '
                'as no suitable formats were found:'), bad)
            d.exec_()
Exemple #17
0
    def __init__(self, input, output, log, report_progress=DummyReporter(),
            dummy=False, merge_plugin_recs=True, abort_after_input_dump=False,
            override_input_metadata=False):
        '''
        :param input: Path to input file.
        :param output: Path to output file/directory
        '''
        if isbytestring(input):
            input = input.decode(filesystem_encoding)
        if isbytestring(output):
            output = output.decode(filesystem_encoding)
        self.original_input_arg = input
        self.input = os.path.abspath(input)
        self.output = os.path.abspath(output)
        self.log = log
        self.ui_reporter = report_progress
        self.abort_after_input_dump = abort_after_input_dump
        self.override_input_metadata = override_input_metadata

        # Pipeline options {{{
        # Initialize the conversion options that are independent of input and
        # output formats. The input and output plugins can still disable these
        # options via recommendations.
        self.pipeline_options = [

OptionRecommendation(name='verbose',
            recommended_value=0, level=OptionRecommendation.LOW,
            short_switch='v',
            help=_('Level of verbosity. Specify multiple times for greater '
                   'verbosity.')
        ),

OptionRecommendation(name='debug_pipeline',
            recommended_value=None, level=OptionRecommendation.LOW,
            short_switch='d',
            help=_('Save the output from different stages of the conversion '
                   'pipeline to the specified '
                   'directory. Useful if you are unsure at which stage '
                   'of the conversion process a bug is occurring.')
        ),

OptionRecommendation(name='input_profile',
            recommended_value='default', level=OptionRecommendation.LOW,
            choices=[x.short_name for x in input_profiles()],
            help=_('Specify the input profile. The input profile gives the '
                   'conversion system information on how to interpret '
                   'various information in the input document. For '
                   'example resolution dependent lengths (i.e. lengths in '
                   'pixels). Choices are:')+\
                        ', '.join([x.short_name for x in input_profiles()])
        ),

OptionRecommendation(name='output_profile',
            recommended_value='default', level=OptionRecommendation.LOW,
            choices=[x.short_name for x in output_profiles()],
            help=_('Specify the output profile. The output profile '
                   'tells the conversion system how to optimize the '
                   'created document for the specified device. In some cases, '
                   'an output profile is required to produce documents that '
                   'will work on a device. For example EPUB on the SONY reader. '
                   'Choices are:') + \
                           ', '.join([x.short_name for x in output_profiles()])
        ),

OptionRecommendation(name='base_font_size',
            recommended_value=0, level=OptionRecommendation.LOW,
            help=_('The base font size in pts. All font sizes in the produced book '
                   'will be rescaled based on this size. By choosing a larger '
                   'size you can make the fonts in the output bigger and vice '
                   'versa. By default, the base font size is chosen based on '
                   'the output profile you chose.'
                   )
        ),

OptionRecommendation(name='font_size_mapping',
            recommended_value=None, level=OptionRecommendation.LOW,
            help=_('Mapping from CSS font names to font sizes in pts. '
                   'An example setting is 12,12,14,16,18,20,22,24. '
                   'These are the mappings for the sizes xx-small to xx-large, '
                   'with the final size being for huge fonts. The font '
                   'rescaling algorithm uses these sizes to intelligently '
                   'rescale fonts. The default is to use a mapping based on '
                   'the output profile you chose.'
                   )
        ),

OptionRecommendation(name='disable_font_rescaling',
            recommended_value=False, level=OptionRecommendation.LOW,
            help=_('Disable all rescaling of font sizes.'
                   )
        ),

OptionRecommendation(name='minimum_line_height',
            recommended_value=120.0, level=OptionRecommendation.LOW,
            help=_(
            'The minimum line height, as a percentage of the element\'s '
            'calculated font size. calibre will ensure that every element '
            'has a line height of at least this setting, irrespective of '
            'what the input document specifies. Set to zero to disable. '
            'Default is 120%. Use this setting in preference to '
            'the direct line height specification, unless you know what '
            'you are doing. For example, you can achieve "double spaced" '
            'text by setting this to 240.'
            )
        ),


OptionRecommendation(name='line_height',
            recommended_value=0, level=OptionRecommendation.LOW,
            help=_(
            'The line height in pts. Controls spacing between consecutive '
            'lines of text. Only applies to elements that do not define '
            'their own line height. In most cases, the minimum line height '
            'option is more useful. '
            'By default no line height manipulation is performed.'
            )
        ),

OptionRecommendation(name='linearize_tables',
            recommended_value=False, level=OptionRecommendation.LOW,
            help=_('Some badly designed documents use tables to control the '
                'layout of text on the page. When converted these documents '
                'often have text that runs off the page and other artifacts. '
                'This option will extract the content from the tables and '
                'present it in a linear fashion.'
                )
        ),

OptionRecommendation(name='level1_toc',
            recommended_value=None, level=OptionRecommendation.LOW,
            help=_('XPath expression that specifies all tags that '
            'should be added to the Table of Contents at level one. If '
            'this is specified, it takes precedence over other forms '
            'of auto-detection.'
            ' See the XPath Tutorial in the calibre User Manual for examples.'
                )
        ),

OptionRecommendation(name='level2_toc',
            recommended_value=None, level=OptionRecommendation.LOW,
            help=_('XPath expression that specifies all tags that should be '
            'added to the Table of Contents at level two. Each entry is added '
            'under the previous level one entry.'
            ' See the XPath Tutorial in the calibre User Manual for examples.'
                )
        ),

OptionRecommendation(name='level3_toc',
            recommended_value=None, level=OptionRecommendation.LOW,
            help=_('XPath expression that specifies all tags that should be '
                'added to the Table of Contents at level three. Each entry '
                'is added under the previous level two entry.'
            ' See the XPath Tutorial in the calibre User Manual for examples.'
                )
        ),

OptionRecommendation(name='use_auto_toc',
            recommended_value=False, level=OptionRecommendation.LOW,
            help=_('Normally, if the source file already has a Table of '
            'Contents, it is used in preference to the auto-generated one. '
            'With this option, the auto-generated one is always used.'
                )
        ),

OptionRecommendation(name='no_chapters_in_toc',
            recommended_value=False, level=OptionRecommendation.LOW,
            help=_("Don't add auto-detected chapters to the Table of "
            'Contents.'
                )
        ),

OptionRecommendation(name='toc_threshold',
            recommended_value=6, level=OptionRecommendation.LOW,
            help=_(
        'If fewer than this number of chapters is detected, then links '
        'are added to the Table of Contents. Default: %default')
        ),

OptionRecommendation(name='max_toc_links',
            recommended_value=50, level=OptionRecommendation.LOW,
            help=_('Maximum number of links to insert into the TOC. Set to 0 '
               'to disable. Default is: %default. Links are only added to the '
            'TOC if less than the threshold number of chapters were detected.'
                )
        ),

OptionRecommendation(name='toc_filter',
            recommended_value=None, level=OptionRecommendation.LOW,
            help=_('Remove entries from the Table of Contents whose titles '
            'match the specified regular expression. Matching entries and all '
            'their children are removed.'
                )
        ),

OptionRecommendation(name='duplicate_links_in_toc',
            recommended_value=False, level=OptionRecommendation.LOW,
            help=_('When creating a TOC from links in the input document, '
                'allow duplicate entries, i.e. allow more than one entry '
                'with the same text, provided that they point to a '
                'different location.')
        ),


OptionRecommendation(name='chapter',
        recommended_value="//*[((name()='h1' or name()='h2') and "
              r"re:test(., '\s*((chapter|book|section|part)\s+)|((prolog|prologue|epilogue)(\s+|$))', 'i')) or @class "
              "= 'chapter']", level=OptionRecommendation.LOW,
            help=_('An XPath expression to detect chapter titles. The default '
                'is to consider <h1> or <h2> tags that contain the words '
                '"chapter","book","section", "prologue", "epilogue", or "part" as chapter titles as '
                'well as any tags that have class="chapter". The expression '
                'used must evaluate to a list of elements. To disable chapter '
                'detection, use the expression "/". See the XPath Tutorial '
                'in the calibre User Manual for further help on using this '
                'feature.'
                )
        ),

OptionRecommendation(name='chapter_mark',
            recommended_value='pagebreak', level=OptionRecommendation.LOW,
            choices=['pagebreak', 'rule', 'both', 'none'],
            help=_('Specify how to mark detected chapters. A value of '
                    '"pagebreak" will insert page breaks before chapters. '
                    'A value of "rule" will insert a line before chapters. '
                    'A value of "none" will disable chapter marking and a '
                    'value of "both" will use both page breaks and lines '
                    'to mark chapters.')
        ),

OptionRecommendation(name='extra_css',
            recommended_value=None, level=OptionRecommendation.LOW,
            help=_('Either the path to a CSS stylesheet or raw CSS. '
                'This CSS will be appended to the style rules from '
                'the source file, so it can be used to override those '
                'rules.')
        ),

OptionRecommendation(name='filter_css',
            recommended_value=None, level=OptionRecommendation.LOW,
            help=_('A comma separated list of CSS properties that '
                'will be removed from all CSS style rules. This is useful '
                'if the presence of some style information prevents it '
                'from being overridden on your device. '
                'For example: '
                'font-family,color,margin-left,margin-right')
        ),

OptionRecommendation(name='page_breaks_before',
            recommended_value="//*[name()='h1' or name()='h2']",
            level=OptionRecommendation.LOW,
            help=_('An XPath expression. Page breaks are inserted '
            'before the specified elements.')
        ),

OptionRecommendation(name='remove_fake_margins',
            recommended_value=True, level=OptionRecommendation.LOW,
            help=_('Some documents specify page margins by '
                'specifying a left and right margin on each individual '
                'paragraph. calibre will try to detect and remove these '
                'margins. Sometimes, this can cause the removal of '
                'margins that should not have been removed. In this '
                'case you can disable the removal.')
        ),


OptionRecommendation(name='margin_top',
        recommended_value=5.0, level=OptionRecommendation.LOW,
        help=_('Set the top margin in pts. Default is %default. '
            'Setting this to less than zero will cause no margin to be set. '
            'Note: 72 pts equals 1 inch')),

OptionRecommendation(name='margin_bottom',
        recommended_value=5.0, level=OptionRecommendation.LOW,
        help=_('Set the bottom margin in pts. Default is %default. '
            'Setting this to less than zero will cause no margin to be set. '
            'Note: 72 pts equals 1 inch')),

OptionRecommendation(name='margin_left',
        recommended_value=5.0, level=OptionRecommendation.LOW,
        help=_('Set the left margin in pts. Default is %default. '
            'Setting this to less than zero will cause no margin to be set. '
            'Note: 72 pts equals 1 inch')),

OptionRecommendation(name='margin_right',
        recommended_value=5.0, level=OptionRecommendation.LOW,
        help=_('Set the right margin in pts. Default is %default. '
            'Setting this to less than zero will cause no margin to be set. '
            'Note: 72 pts equals 1 inch')),

OptionRecommendation(name='change_justification',
        recommended_value='original', level=OptionRecommendation.LOW,
        choices=['left','justify','original'],
        help=_('Change text justification. A value of "left" converts all'
            ' justified text in the source to left aligned (i.e. '
            'unjustified) text. A value of "justify" converts all '
            'unjustified text to justified. A value of "original" '
            '(the default) does not change justification in the '
            'source file. Note that only some output formats support '
            'justification.')),

OptionRecommendation(name='remove_paragraph_spacing',
        recommended_value=False, level=OptionRecommendation.LOW,
        help=_('Remove spacing between paragraphs. Also sets an indent on '
        'paragraphs of 1.5em. Spacing removal will not work '
        'if the source file does not use paragraphs (<p> or <div> tags).')
        ),

OptionRecommendation(name='remove_paragraph_spacing_indent_size',
        recommended_value=1.5, level=OptionRecommendation.LOW,
        help=_('When calibre removes blank lines between paragraphs, it automatically '
            'sets a paragraph indent, to ensure that paragraphs can be easily '
            'distinguished. This option controls the width of that indent (in em). '
            'If you set this value negative, then the indent specified in the input '
            'document is used, that is, calibre does not change the indentation.')
        ),

OptionRecommendation(name='prefer_metadata_cover',
        recommended_value=False, level=OptionRecommendation.LOW,
        help=_('Use the cover detected from the source file in preference '
        'to the specified cover.')
        ),

OptionRecommendation(name='insert_blank_line',
        recommended_value=False, level=OptionRecommendation.LOW,
        help=_('Insert a blank line between paragraphs. Will not work '
            'if the source file does not use paragraphs (<p> or <div> tags).'
            )
        ),

OptionRecommendation(name='insert_blank_line_size',
        recommended_value=0.5, level=OptionRecommendation.LOW,
        help=_('Set the height of the inserted blank lines (in em).'
            ' The height of the lines between paragraphs will be twice the value'
            ' set here.')
        ),

OptionRecommendation(name='remove_first_image',
        recommended_value=False, level=OptionRecommendation.LOW,
        help=_('Remove the first image from the input ebook. Useful if the '
        'input document has a cover image that is not identified as a cover. '
        'In this case, if you set a cover in calibre, the output document will '
        'end up with two cover images if you do not specify this option.'
            )
        ),

OptionRecommendation(name='insert_metadata',
        recommended_value=False, level=OptionRecommendation.LOW,
        help=_('Insert the book metadata at the start of '
            'the book. This is useful if your ebook reader does not support '
            'displaying/searching metadata directly.'
            )
        ),

OptionRecommendation(name='smarten_punctuation',
        recommended_value=False, level=OptionRecommendation.LOW,
        help=_('Convert plain quotes, dashes and ellipsis to their '
            'typographically correct equivalents. For details, see '
            'http://daringfireball.net/projects/smartypants'
            )
        ),

OptionRecommendation(name='unsmarten_punctuation',
        recommended_value=False, level=OptionRecommendation.LOW,
        help=_('Convert fancy quotes, dashes and ellipsis to their '
               'plain equivalents.'
            )
        ),

OptionRecommendation(name='read_metadata_from_opf',
            recommended_value=None, level=OptionRecommendation.LOW,
            short_switch='m',
            help=_('Read metadata from the specified OPF file. Metadata read '
                   'from this file will override any metadata in the source '
                   'file.')
        ),

OptionRecommendation(name='asciiize',
        recommended_value=False, level=OptionRecommendation.LOW,
        help=(_('Transliterate unicode characters to an ASCII '
            'representation. Use with care because this will replace '
            'unicode characters with ASCII. For instance it will replace "%s" '
            'with "Mikhail Gorbachiov". Also, note that in '
            'cases where there are multiple representations of a character '
            '(characters shared by Chinese and Japanese for instance) the '
            'representation based on the current calibre interface language will be '
            'used.')%\
            u'\u041c\u0438\u0445\u0430\u0438\u043b '
            u'\u0413\u043e\u0440\u0431\u0430\u0447\u0451\u0432'
)
        ),

OptionRecommendation(name='keep_ligatures',
            recommended_value=False, level=OptionRecommendation.LOW,
            help=_('Preserve ligatures present in the input document. '
                'A ligature is a special rendering of a pair of '
                'characters like ff, fi, fl et cetera. '
                'Most readers do not have support for '
                'ligatures in their default fonts, so they are '
                'unlikely to render correctly. By default, calibre '
                'will turn a ligature into the corresponding pair of normal '
                'characters. This option will preserve them instead.')
        ),

OptionRecommendation(name='title',
    recommended_value=None, level=OptionRecommendation.LOW,
    help=_('Set the title.')),

OptionRecommendation(name='authors',
    recommended_value=None, level=OptionRecommendation.LOW,
    help=_('Set the authors. Multiple authors should be separated by '
    'ampersands.')),

OptionRecommendation(name='title_sort',
    recommended_value=None, level=OptionRecommendation.LOW,
    help=_('The version of the title to be used for sorting. ')),

OptionRecommendation(name='author_sort',
    recommended_value=None, level=OptionRecommendation.LOW,
    help=_('String to be used when sorting by author. ')),

OptionRecommendation(name='cover',
    recommended_value=None, level=OptionRecommendation.LOW,
    help=_('Set the cover to the specified file or URL')),

OptionRecommendation(name='comments',
    recommended_value=None, level=OptionRecommendation.LOW,
    help=_('Set the ebook description.')),

OptionRecommendation(name='publisher',
    recommended_value=None, level=OptionRecommendation.LOW,
    help=_('Set the ebook publisher.')),

OptionRecommendation(name='series',
    recommended_value=None, level=OptionRecommendation.LOW,
    help=_('Set the series this ebook belongs to.')),

OptionRecommendation(name='series_index',
    recommended_value=None, level=OptionRecommendation.LOW,
    help=_('Set the index of the book in this series.')),

OptionRecommendation(name='rating',
    recommended_value=None, level=OptionRecommendation.LOW,
    help=_('Set the rating. Should be a number between 1 and 5.')),

OptionRecommendation(name='isbn',
    recommended_value=None, level=OptionRecommendation.LOW,
    help=_('Set the ISBN of the book.')),

OptionRecommendation(name='tags',
    recommended_value=None, level=OptionRecommendation.LOW,
    help=_('Set the tags for the book. Should be a comma separated list.')),

OptionRecommendation(name='book_producer',
    recommended_value=None, level=OptionRecommendation.LOW,
    help=_('Set the book producer.')),

OptionRecommendation(name='language',
    recommended_value=None, level=OptionRecommendation.LOW,
    help=_('Set the language.')),

OptionRecommendation(name='pubdate',
    recommended_value=None, level=OptionRecommendation.LOW,
    help=_('Set the publication date.')),

OptionRecommendation(name='timestamp',
    recommended_value=None, level=OptionRecommendation.LOW,
    help=_('Set the book timestamp (no longer used anywhere)')),

OptionRecommendation(name='enable_heuristics',
    recommended_value=False, level=OptionRecommendation.LOW,
    help=_('Enable heuristic processing. This option must be set for any '
           'heuristic processing to take place.')),

OptionRecommendation(name='markup_chapter_headings',
    recommended_value=True, level=OptionRecommendation.LOW,
    help=_('Detect unformatted chapter headings and sub headings. Change '
           'them to h2 and h3 tags.  This setting will not create a TOC, '
           'but can be used in conjunction with structure detection to create '
           'one.')),

OptionRecommendation(name='italicize_common_cases',
    recommended_value=True, level=OptionRecommendation.LOW,
    help=_('Look for common words and patterns that denote '
           'italics and italicize them.')),

OptionRecommendation(name='fix_indents',
    recommended_value=True, level=OptionRecommendation.LOW,
    help=_('Turn indentation created from multiple non-breaking space entities '
           'into CSS indents.')),

OptionRecommendation(name='html_unwrap_factor',
    recommended_value=0.40, level=OptionRecommendation.LOW,
    help=_('Scale used to determine the length at which a line should '
            'be unwrapped. Valid values are a decimal between 0 and 1. The '
            'default is 0.4, just below the median line length.  If only a '
            'few lines in the document require unwrapping this value should '
            'be reduced')),

OptionRecommendation(name='unwrap_lines',
    recommended_value=True, level=OptionRecommendation.LOW,
    help=_('Unwrap lines using punctuation and other formatting clues.')),

OptionRecommendation(name='delete_blank_paragraphs',
    recommended_value=True, level=OptionRecommendation.LOW,
    help=_('Remove empty paragraphs from the document when they exist between '
           'every other paragraph')),

OptionRecommendation(name='format_scene_breaks',
    recommended_value=True, level=OptionRecommendation.LOW,
    help=_('Left aligned scene break markers are center aligned. '
           'Replace soft scene breaks that use multiple blank lines with '
           'horizontal rules.')),

OptionRecommendation(name='replace_scene_breaks',
    recommended_value='', level=OptionRecommendation.LOW,
    help=_('Replace scene breaks with the specified text. By default, the '
        'text from the input document is used.')),

OptionRecommendation(name='dehyphenate',
    recommended_value=True, level=OptionRecommendation.LOW,
    help=_('Analyze hyphenated words throughout the document.  The '
           'document itself is used as a dictionary to determine whether hyphens '
           'should be retained or removed.')),

OptionRecommendation(name='renumber_headings',
    recommended_value=True, level=OptionRecommendation.LOW,
    help=_('Looks for occurrences of sequential <h1> or <h2> tags. '
           'The tags are renumbered to prevent splitting in the middle '
           'of chapter headings.')),

OptionRecommendation(name='sr1_search',
    recommended_value='', level=OptionRecommendation.LOW,
    help=_('Search pattern (regular expression) to be replaced with '
           'sr1-replace.')),

OptionRecommendation(name='sr1_replace',
    recommended_value='', level=OptionRecommendation.LOW,
    help=_('Replacement to replace the text found with sr1-search.')),

OptionRecommendation(name='sr2_search',
    recommended_value='', level=OptionRecommendation.LOW,
    help=_('Search pattern (regular expression) to be replaced with '
           'sr2-replace.')),

OptionRecommendation(name='sr2_replace',
    recommended_value='', level=OptionRecommendation.LOW,
    help=_('Replacement to replace the text found with sr2-search.')),

OptionRecommendation(name='sr3_search',
    recommended_value='', level=OptionRecommendation.LOW,
    help=_('Search pattern (regular expression) to be replaced with '
           'sr3-replace.')),

OptionRecommendation(name='sr3_replace',
    recommended_value='', level=OptionRecommendation.LOW,
    help=_('Replacement to replace the text found with sr3-search.')),

OptionRecommendation(name='search_replace',
    recommended_value=None, level=OptionRecommendation.LOW, help=_(
        'Path to a file containing search and replace regular expressions. '
        'The file must contain alternating lines of regular expression '
        'followed by replacement pattern (which can be an empty line). '
        'The regular expression must be in the python regex syntax and '
        'the file must be UTF-8 encoded.')),
]
        # }}}

        input_fmt = os.path.splitext(self.input)[1]
        if not input_fmt:
            raise ValueError('Input file must have an extension')
        input_fmt = input_fmt[1:].lower().replace('original_', '')
        self.archive_input_tdir = None
        if input_fmt in ARCHIVE_FMTS:
            self.log('Processing archive...')
            tdir = PersistentTemporaryDirectory('_plumber_archive')
            self.input, input_fmt = self.unarchive(self.input, tdir)
            self.archive_input_tdir = tdir
        if os.access(self.input, os.R_OK):
            nfp = run_plugins_on_preprocess(self.input, input_fmt)
            if nfp != self.input:
                self.input = nfp
                input_fmt = os.path.splitext(self.input)[1]
                if not input_fmt:
                    raise ValueError('Input file must have an extension')
                input_fmt = input_fmt[1:].lower()

        if os.path.exists(self.output) and os.path.isdir(self.output):
            output_fmt = 'oeb'
        else:
            output_fmt = os.path.splitext(self.output)[1]
            if not output_fmt:
                output_fmt = '.oeb'
            output_fmt = output_fmt[1:].lower()

        self.input_plugin  = plugin_for_input_format(input_fmt)
        self.output_plugin = plugin_for_output_format(output_fmt)

        if self.input_plugin is None:
            raise ValueError('No plugin to handle input format: '+input_fmt)

        if self.output_plugin is None:
            raise ValueError('No plugin to handle output format: '+output_fmt)

        self.input_fmt = input_fmt
        self.output_fmt = output_fmt


        self.all_format_options = set()
        self.input_options = set()
        self.output_options = set()
        # Build set of all possible options. Two options are equal if their
        # names are the same.
        if not dummy:
            self.input_options  = self.input_plugin.options.union(
                                        self.input_plugin.common_options)
            self.output_options = self.output_plugin.options.union(
                                    self.output_plugin.common_options)
        else:
            for fmt in available_input_formats():
                input_plugin = plugin_for_input_format(fmt)
                if input_plugin:
                    self.all_format_options = self.all_format_options.union(
                        input_plugin.options.union(input_plugin.common_options))
            for fmt in available_output_formats():
                output_plugin = plugin_for_output_format(fmt)
                if output_plugin:
                    self.all_format_options = self.all_format_options.union(
                        output_plugin.options.union(output_plugin.common_options))

        # Remove the options that have been disabled by recommendations from the
        # plugins.
        for w in ('input_options', 'output_options',
                'all_format_options'):
            temp = set([])
            for x in getattr(self, w):
                temp.add(x.clone())
            setattr(self, w, temp)
        if merge_plugin_recs:
            self.merge_plugin_recommendations()
Exemple #18
0
    def run(self, opts):
        from calibre.utils.serialize import msgpack_dumps
        scripts = {}
        for x in ('console', 'gui'):
            for name in basenames[x]:
                if name in ('calibre-complete', 'calibre_postinstall'):
                    continue
                scripts[name] = x

        dest = self.j(self.RESOURCES, 'scripts.calibre_msgpack')
        if self.newer(dest, self.j(self.SRC, 'calibre', 'linux.py')):
            self.info('\tCreating ' + self.b(dest))
            with open(dest, 'wb') as f:
                f.write(msgpack_dumps(scripts))

        from calibre.web.feeds.recipes.collection import \
                serialize_builtin_recipes, iterate_over_builtin_recipe_files

        files = [x[1] for x in iterate_over_builtin_recipe_files()]

        dest = self.j(self.RESOURCES, 'builtin_recipes.xml')
        if self.newer(dest, files):
            self.info('\tCreating builtin_recipes.xml')
            xml = serialize_builtin_recipes()
            with open(dest, 'wb') as f:
                f.write(xml)

        recipe_icon_dir = self.a(
            self.j(self.RESOURCES, '..', 'recipes', 'icons'))
        dest = os.path.splitext(dest)[0] + '.zip'
        files += glob.glob(self.j(recipe_icon_dir, '*.png'))
        if self.newer(dest, files):
            self.info('\tCreating builtin_recipes.zip')
            with zipfile.ZipFile(dest, 'w', zipfile.ZIP_STORED) as zf:
                for n in sorted(files, key=self.b):
                    with open(n, 'rb') as f:
                        zf.writestr(self.b(n), f.read())

        dest = self.j(self.RESOURCES, 'ebook-convert-complete.calibre_msgpack')
        files = []
        for x in os.walk(self.j(self.SRC, 'calibre')):
            for f in x[-1]:
                if f.endswith('.py'):
                    files.append(self.j(x[0], f))
        if self.newer(dest, files):
            self.info('\tCreating ' + self.b(dest))
            complete = {}
            from calibre.ebooks.conversion.plumber import supported_input_formats
            complete['input_fmts'] = set(supported_input_formats())
            from calibre.web.feeds.recipes.collection import get_builtin_recipe_titles
            complete['input_recipes'] = [
                t + '.recipe ' for t in get_builtin_recipe_titles()
            ]
            from calibre.customize.ui import available_output_formats
            complete['output'] = set(available_output_formats())
            from calibre.ebooks.conversion.cli import create_option_parser
            from calibre.utils.logging import Log
            log = Log()
            # log.outputs = []
            for inf in supported_input_formats():
                if inf in ('zip', 'rar', 'oebzip'):
                    continue
                for ouf in available_output_formats():
                    of = ouf if ouf == 'oeb' else 'dummy.' + ouf
                    p = create_option_parser(('ec', 'dummy1.' + inf, of, '-h'),
                                             log)[0]
                    complete[(inf, ouf)] = [
                        x + ' ' for x in get_opts_from_parser(p)
                    ]

            with open(dest, 'wb') as f:
                f.write(msgpack_dumps(only_unicode_recursive(complete)))

        self.info('\tCreating template-functions.json')
        dest = self.j(self.RESOURCES, 'template-functions.json')
        function_dict = {}
        import inspect
        from calibre.utils.formatter_functions import formatter_functions
        for obj in formatter_functions().get_builtins().values():
            eval_func = inspect.getmembers(
                obj,
                lambda x: inspect.ismethod(x) and x.__name__ == 'evaluate')
            try:
                lines = [
                    l[4:] for l in inspect.getsourcelines(eval_func[0][1])[0]
                ]
            except:
                continue
            lines = ''.join(lines)
            function_dict[obj.name] = lines
        dump_json(function_dict, dest)

        self.info('\tCreating editor-functions.json')
        dest = self.j(self.RESOURCES, 'editor-functions.json')
        function_dict = {}
        from calibre.gui2.tweak_book.function_replace import builtin_functions
        for func in builtin_functions():
            try:
                src = ''.join(inspect.getsourcelines(func)[0][1:])
            except Exception:
                continue
            src = src.replace('def ' + func.__name__, 'def replace')
            imports = [
                f'from {x.__module__} import {x.__name__}'
                for x in func.imports
            ]
            if imports:
                src = '\n'.join(imports) + '\n\n' + src
            function_dict[func.name] = src
        dump_json(function_dict, dest)
        self.info('\tCreating user-manual-translation-stats.json')
        d = {}
        for lc, stats in iteritems(
                json.load(
                    open(
                        self.j(self.d(self.SRC), 'manual', 'locale',
                               'completed.json')))):
            total = sum(itervalues(stats))
            d[lc] = stats['translated'] / float(total)
        dump_json(d,
                  self.j(self.RESOURCES, 'user-manual-translation-stats.json'))

        src = self.j(self.SRC, '..', 'Changelog.txt')
        dest = self.j(self.RESOURCES, 'changelog.json')
        if self.newer(dest, [src]):
            self.info('\tCreating changelog.json')
            from setup.changelog import parse
            with open(src, encoding='utf-8') as f:
                dump_json(parse(f.read(), parse_dates=False), dest)
Exemple #19
0
    def run(self, opts):
        scripts = {}
        for x in ('console', 'gui'):
            for name in basenames[x]:
                if name in ('calibre-complete', 'calibre_postinstall'):
                    continue
                scripts[name] = x

        dest = self.j(self.RESOURCES, 'scripts.pickle')
        if self.newer(dest, self.j(self.SRC, 'calibre', 'linux.py')):
            self.info('\tCreating scripts.pickle')
            f = open(dest, 'wb')
            cPickle.dump(scripts, f, -1)

        from calibre.web.feeds.recipes.collection import \
                serialize_builtin_recipes, iterate_over_builtin_recipe_files

        files = [x[1] for x in iterate_over_builtin_recipe_files()]

        dest = self.j(self.RESOURCES, 'builtin_recipes.xml')
        if self.newer(dest, files):
            self.info('\tCreating builtin_recipes.xml')
            xml = serialize_builtin_recipes()
            with open(dest, 'wb') as f:
                f.write(xml)

        recipe_icon_dir = self.a(
            self.j(self.RESOURCES, '..', 'recipes', 'icons'))
        dest = os.path.splitext(dest)[0] + '.zip'
        files += glob.glob(self.j(recipe_icon_dir, '*.png'))
        if self.newer(dest, files):
            self.info('\tCreating builtin_recipes.zip')
            with zipfile.ZipFile(dest, 'w', zipfile.ZIP_STORED) as zf:
                for n in sorted(files, key=self.b):
                    with open(n, 'rb') as f:
                        zf.writestr(os.path.basename(n), f.read())

        dest = self.j(self.RESOURCES, 'ebook-convert-complete.pickle')
        files = []
        for x in os.walk(self.j(self.SRC, 'calibre')):
            for f in x[-1]:
                if f.endswith('.py'):
                    files.append(self.j(x[0], f))
        if self.newer(dest, files):
            self.info('\tCreating ebook-convert-complete.pickle')
            complete = {}
            from calibre.ebooks.conversion.plumber import supported_input_formats
            complete['input_fmts'] = set(supported_input_formats())
            from calibre.web.feeds.recipes.collection import get_builtin_recipe_titles
            complete['input_recipes'] = [
                t + '.recipe ' for t in get_builtin_recipe_titles()
            ]
            from calibre.customize.ui import available_output_formats
            complete['output'] = set(available_output_formats())
            from calibre.ebooks.conversion.cli import create_option_parser
            from calibre.utils.logging import Log
            log = Log()
            #log.outputs = []
            for inf in supported_input_formats():
                if inf in ('zip', 'rar', 'oebzip'):
                    continue
                for ouf in available_output_formats():
                    of = ouf if ouf == 'oeb' else 'dummy.' + ouf
                    p = create_option_parser(('ec', 'dummy1.' + inf, of, '-h'),
                                             log)[0]
                    complete[(inf, ouf)] = [
                        x + ' ' for x in get_opts_from_parser(p)
                    ]

            cPickle.dump(complete, open(dest, 'wb'), -1)

        self.info('\tCreating template-functions.json')
        dest = self.j(self.RESOURCES, 'template-functions.json')
        function_dict = {}
        import inspect
        from calibre.utils.formatter_functions import formatter_functions
        for obj in formatter_functions().get_builtins().values():
            eval_func = inspect.getmembers(
                obj,
                lambda x: inspect.ismethod(x) and x.__name__ == 'evaluate')
            try:
                lines = [
                    l[4:] for l in inspect.getsourcelines(eval_func[0][1])[0]
                ]
            except:
                continue
            lines = ''.join(lines)
            function_dict[obj.name] = lines
        import json
        json.dump(function_dict, open(dest, 'wb'), indent=4)
Exemple #20
0
    def run(self, opts):
        scripts = {}
        for x in ('console', 'gui'):
            for name in basenames[x]:
                if name in ('calibre-complete', 'calibre_postinstall'):
                    continue
                scripts[name] = x

        dest = self.j(self.RESOURCES, 'scripts.pickle')
        if self.newer(dest, self.j(self.SRC, 'calibre', 'linux.py')):
            self.info('\tCreating scripts.pickle')
            f = open(dest, 'wb')
            cPickle.dump(scripts, f, -1)

        from calibre.web.feeds.recipes.collection import \
                serialize_builtin_recipes, iterate_over_builtin_recipe_files

        files = [x[1] for x in iterate_over_builtin_recipe_files()]

        dest = self.j(self.RESOURCES, 'builtin_recipes.xml')
        if self.newer(dest, files):
            self.info('\tCreating builtin_recipes.xml')
            xml = serialize_builtin_recipes()
            with open(dest, 'wb') as f:
                f.write(xml)

        recipe_icon_dir = self.a(self.j(self.RESOURCES, '..', 'recipes',
            'icons'))
        dest = os.path.splitext(dest)[0] + '.zip'
        files += glob.glob(self.j(recipe_icon_dir, '*.png'))
        if self.newer(dest, files):
            self.info('\tCreating builtin_recipes.zip')
            with zipfile.ZipFile(dest, 'w', zipfile.ZIP_STORED) as zf:
                for n in sorted(files, key=self.b):
                    with open(n, 'rb') as f:
                        zf.writestr(os.path.basename(n), f.read())

        dest = self.j(self.RESOURCES, 'ebook-convert-complete.pickle')
        files = []
        for x in os.walk(self.j(self.SRC, 'calibre')):
            for f in x[-1]:
                if f.endswith('.py'):
                    files.append(self.j(x[0], f))
        if self.newer(dest, files):
            self.info('\tCreating ebook-convert-complete.pickle')
            complete = {}
            from calibre.ebooks.conversion.plumber import supported_input_formats
            complete['input_fmts'] = set(supported_input_formats())
            from calibre.web.feeds.recipes.collection import get_builtin_recipe_titles
            complete['input_recipes'] = [t+'.recipe ' for t in
                    get_builtin_recipe_titles()]
            from calibre.customize.ui import available_output_formats
            complete['output'] = set(available_output_formats())
            from calibre.ebooks.conversion.cli import create_option_parser
            from calibre.utils.logging import Log
            log = Log()
            # log.outputs = []
            for inf in supported_input_formats():
                if inf in ('zip', 'rar', 'oebzip'):
                    continue
                for ouf in available_output_formats():
                    of = ouf if ouf == 'oeb' else 'dummy.'+ouf
                    p = create_option_parser(('ec', 'dummy1.'+inf, of, '-h'),
                            log)[0]
                    complete[(inf, ouf)] = [x+' 'for x in
                            get_opts_from_parser(p)]

            cPickle.dump(complete, open(dest, 'wb'), -1)

        self.info('\tCreating template-functions.json')
        dest = self.j(self.RESOURCES, 'template-functions.json')
        function_dict = {}
        import inspect
        from calibre.utils.formatter_functions import formatter_functions
        for obj in formatter_functions().get_builtins().values():
            eval_func = inspect.getmembers(obj,
                    lambda x: inspect.ismethod(x) and x.__name__ == 'evaluate')
            try:
                lines = [l[4:] for l in inspect.getsourcelines(eval_func[0][1])[0]]
            except:
                continue
            lines = ''.join(lines)
            function_dict[obj.name] = lines
        import json
        json.dump(function_dict, open(dest, 'wb'), indent=4)
Exemple #21
0
    def run(self, opts):
        scripts = {}
        for x in ("console", "gui"):
            for name in basenames[x]:
                if name in ("calibre-complete", "calibre_postinstall"):
                    continue
                scripts[name] = x

        dest = self.j(self.RESOURCES, "scripts.pickle")
        if self.newer(dest, self.j(self.SRC, "calibre", "linux.py")):
            self.info("\tCreating scripts.pickle")
            f = open(dest, "wb")
            cPickle.dump(scripts, f, -1)

        from calibre.web.feeds.recipes.collection import serialize_builtin_recipes, iterate_over_builtin_recipe_files

        files = [x[1] for x in iterate_over_builtin_recipe_files()]

        dest = self.j(self.RESOURCES, "builtin_recipes.xml")
        if self.newer(dest, files):
            self.info("\tCreating builtin_recipes.xml")
            xml = serialize_builtin_recipes()
            with open(dest, "wb") as f:
                f.write(xml)

        recipe_icon_dir = self.a(self.j(self.RESOURCES, "..", "recipes", "icons"))
        dest = os.path.splitext(dest)[0] + ".zip"
        files += glob.glob(self.j(recipe_icon_dir, "*.png"))
        if self.newer(dest, files):
            self.info("\tCreating builtin_recipes.zip")
            with zipfile.ZipFile(dest, "w", zipfile.ZIP_STORED) as zf:
                for n in sorted(files, key=self.b):
                    with open(n, "rb") as f:
                        zf.writestr(os.path.basename(n), f.read())

        dest = self.j(self.RESOURCES, "ebook-convert-complete.pickle")
        files = []
        for x in os.walk(self.j(self.SRC, "calibre")):
            for f in x[-1]:
                if f.endswith(".py"):
                    files.append(self.j(x[0], f))
        if self.newer(dest, files):
            self.info("\tCreating ebook-convert-complete.pickle")
            complete = {}
            from calibre.ebooks.conversion.plumber import supported_input_formats

            complete["input_fmts"] = set(supported_input_formats())
            from calibre.web.feeds.recipes.collection import get_builtin_recipe_titles

            complete["input_recipes"] = [t + ".recipe " for t in get_builtin_recipe_titles()]
            from calibre.customize.ui import available_output_formats

            complete["output"] = set(available_output_formats())
            from calibre.ebooks.conversion.cli import create_option_parser
            from calibre.utils.logging import Log

            log = Log()
            # log.outputs = []
            for inf in supported_input_formats():
                if inf in ("zip", "rar", "oebzip"):
                    continue
                for ouf in available_output_formats():
                    of = ouf if ouf == "oeb" else "dummy." + ouf
                    p = create_option_parser(("ec", "dummy1." + inf, of, "-h"), log)[0]
                    complete[(inf, ouf)] = [x + " " for x in get_opts_from_parser(p)]

            cPickle.dump(complete, open(dest, "wb"), -1)

        self.info("\tCreating template-functions.json")
        dest = self.j(self.RESOURCES, "template-functions.json")
        function_dict = {}
        import inspect
        from calibre.utils.formatter_functions import formatter_functions

        for obj in formatter_functions().get_builtins().values():
            eval_func = inspect.getmembers(obj, lambda x: inspect.ismethod(x) and x.__name__ == "evaluate")
            try:
                lines = [l[4:] for l in inspect.getsourcelines(eval_func[0][1])[0]]
            except:
                continue
            lines = "".join(lines)
            function_dict[obj.name] = lines
        import json

        json.dump(function_dict, open(dest, "wb"), indent=4)