Exemplo n.º 1
0
def interface_data(ctx, rd):
    '''
    Return the data needed to create the server main UI

    Optional: ?num=50&sort=timestamp.desc&library_id=<default library>
              &search=''&extra_books=''
    '''
    ans = {
        'username':rd.username,
        'output_format':prefs['output_format'].upper(),
        'input_formats':{x.upper():True for x in available_input_formats()},
        'gui_pubdate_display_format':tweaks['gui_pubdate_display_format'],
        'gui_timestamp_display_format':tweaks['gui_timestamp_display_format'],
        'gui_last_modified_display_format':tweaks['gui_last_modified_display_format'],
        'use_roman_numerals_for_series_number': get_use_roman(),
    }
    ans['library_map'], ans['default_library'] = ctx.library_info(rd)
    ud = {}
    if rd.username:
        # Override session data with stored values for the authenticated user,
        # if any
        ud = ctx.user_manager.get_session_data(rd.username)
        lid = ud.get('library_id')
        if lid and lid in ans['library_map']:
            rd.query.set('library_id', lid)
        usort = ud.get('sort')
        if usort:
            rd.query.set('sort', usort)
    ans['library_id'], db, sorts, orders = get_basic_query_data(ctx, rd)
    ans['user_session_data'] = ud
    try:
        num = int(rd.query.get('num', DEFAULT_NUMBER_OF_BOOKS))
    except Exception:
        raise HTTPNotFound('Invalid number of books: %r' % rd.query.get('num'))
    with db.safe_read_lock:
        try:
            ans['search_result'] = search_result(ctx, rd, db, rd.query.get('search', ''), num, 0, ','.join(sorts), ','.join(orders))
        except ParseException:
            ans['search_result'] = search_result(ctx, rd, db, '', num, 0, ','.join(sorts), ','.join(orders))
        sf = db.field_metadata.ui_sortable_field_keys()
        sf.pop('ondevice', None)
        ans['sortable_fields'] = sorted(((
            sanitize_sort_field_name(db.field_metadata, k), v) for k, v in sf.iteritems()),
                                        key=lambda (field, name):sort_key(name))
        ans['field_metadata'] = db.field_metadata.all_metadata()
        ans['icon_map'] = icon_map()
        ans['icon_path'] = ctx.url_for('/icon', which='')
        mdata = ans['metadata'] = {}
        try:
            extra_books = set(int(x) for x in rd.query.get('extra_books', '').split(','))
        except Exception:
            extra_books = ()
        for coll in (ans['search_result']['book_ids'], extra_books):
            for book_id in coll:
                if book_id not in mdata:
                    data = book_as_json(db, book_id)
                    if data is not None:
                        mdata[book_id] = data

    return ans
Exemplo n.º 2
0
 def open_ebook(self, checked):
     files = choose_files(self, 'ebook viewer open dialog',
                  _('Choose ebook'),
                  [(_('Ebooks'), available_input_formats())],
                  all_files=False,
                  select_only_single_file=True)
     if files:
         self.load_ebook(files[0])
Exemplo n.º 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,
            )
Exemplo n.º 4
0
 def ask_for_open(self, path=None):
     if path is None:
         files = choose_files(
             self, 'ebook viewer open dialog',
             _('Choose e-book'), [(_('E-books'), available_input_formats())],
             all_files=False, select_only_single_file=True)
         if not files:
             return
         path = files[0]
     self.load_ebook(path)
Exemplo n.º 5
0
 def open_ebook(self, checked):
     files = choose_files(
         self,
         "ebook viewer open dialog",
         _("Choose ebook"),
         [(_("Ebooks"), available_input_formats())],
         all_files=False,
         select_only_single_file=True,
     )
     if files:
         self.load_ebook(files[0])
Exemplo n.º 6
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)
Exemplo n.º 7
0
def basic_interface_data(ctx, rd):
    ans = {
        'username':rd.username,
        'output_format':prefs['output_format'].upper(),
        'input_formats':{x.upper():True for x in available_input_formats()},
        'gui_pubdate_display_format':tweaks['gui_pubdate_display_format'],
        'gui_timestamp_display_format':tweaks['gui_timestamp_display_format'],
        'gui_last_modified_display_format':tweaks['gui_last_modified_display_format'],
        'use_roman_numerals_for_series_number': get_use_roman(),
        'translations': get_translations(),
        'allow_console_print':getattr(rd.opts, 'allow_console_print', False),
        'icon_map': icon_map(),
        'icon_path': ctx.url_for('/icon', which=''),
    }
    ans['library_map'], ans['default_library_id'] = ctx.library_info(rd)
    return ans
Exemplo n.º 8
0
    def unarchive(self, path, tdir):
        extract(path, tdir)
        files = list(walk(tdir))
        files = [f if isinstance(f, unicode) else f.decode(filesystem_encoding)
                for f in files]
        from calibre.customize.ui import available_input_formats
        fmts = set(available_input_formats())
        fmts -= {'htm', 'html', 'xhtm', 'xhtml'}
        fmts -= set(ARCHIVE_FMTS)

        for ext in fmts:
            for f in files:
                if f.lower().endswith('.'+ext):
                    if ext in ['txt', 'rtf'] and os.stat(f).st_size < 2048:
                        continue
                    return f, ext
        return self.find_html_index(files)
Exemplo n.º 9
0
def basic_interface_data(ctx, rd):
    ans = {
        'username': rd.username,
        'output_format': prefs['output_format'].upper(),
        'input_formats': {x.upper(): True
                          for x in available_input_formats()},
        'gui_pubdate_display_format': tweaks['gui_pubdate_display_format'],
        'gui_timestamp_display_format': tweaks['gui_timestamp_display_format'],
        'gui_last_modified_display_format': tweaks['gui_last_modified_display_format'],
        'use_roman_numerals_for_series_number': get_use_roman(),
        'translations': get_translations(),
        'icon_map': icon_map(),
        'icon_path': ctx.url_for('/icon', which=''),
        'custom_list_template': getattr(ctx, 'custom_list_template', None) or custom_list_template(),
    }
    ans['library_map'], ans['default_library_id'] = ctx.library_info(rd)
    return ans
Exemplo n.º 10
0
def basic_interface_data(ctx, rd):
    ans = {
        'username': rd.username,
        'output_format': prefs['output_format'].upper(),
        'input_formats': {x.upper(): True
                          for x in available_input_formats()},
        'gui_pubdate_display_format': tweaks['gui_pubdate_display_format'],
        'gui_timestamp_display_format': tweaks['gui_timestamp_display_format'],
        'gui_last_modified_display_format': tweaks['gui_last_modified_display_format'],
        'completion_mode': tweaks['completion_mode'],
        'use_roman_numerals_for_series_number': get_use_roman(),
        'translations': get_translations(),
        'icon_map': icon_map(),
        'icon_path': ctx.url_for('/icon', which=''),
        'custom_list_template': getattr(ctx, 'custom_list_template', None) or custom_list_template(),
        'search_the_net_urls': getattr(ctx, 'search_the_net_urls', None) or [],
        'num_per_page': rd.opts.num_per_page,
        'donate_link': localize_website_link('https://calibre-ebook.com/donate')
    }
    ans['library_map'], ans['default_library_id'] = ctx.library_info(rd)
    return ans
Exemplo n.º 11
0
def basic_interface_data(ctx, rd):
    ans = {
        'username': rd.username,
        'output_format': prefs['output_format'].upper(),
        'input_formats': {x.upper(): True
                          for x in available_input_formats()},
        'gui_pubdate_display_format': tweaks['gui_pubdate_display_format'],
        'gui_timestamp_display_format': tweaks['gui_timestamp_display_format'],
        'gui_last_modified_display_format': tweaks['gui_last_modified_display_format'],
        'completion_mode': tweaks['completion_mode'],
        'use_roman_numerals_for_series_number': get_use_roman(),
        'translations': get_translations(),
        'icon_map': icon_map(),
        'icon_path': ctx.url_for('/icon', which=''),
        'custom_list_template': getattr(ctx, 'custom_list_template', None) or custom_list_template(),
        'search_the_net_urls': getattr(ctx, 'search_the_net_urls', None) or [],
        'num_per_page': rd.opts.num_per_page,
        'default_book_list_mode': rd.opts.book_list_mode,
        'donate_link': localize_website_link('https://calibre-ebook.com/donate')
    }
    ans['library_map'], ans['default_library_id'] = ctx.library_info(rd)
    return ans
Exemplo n.º 12
0
def is_supported(path):
    ext = os.path.splitext(path)[1].replace('.', '').lower()
    ext = re.sub(r'(x{0,1})htm(l{0,1})', 'html', ext)
    return ext in available_input_formats() or ext == 'kepub'
Exemplo n.º 13
0
def write_completion(bash_comp_dest, zsh):
    from calibre.ebooks.metadata.cli import option_parser as metaop, filetypes as meta_filetypes
    from calibre.ebooks.lrf.lrfparser import option_parser as lrf2lrsop
    from calibre.gui2.lrf_renderer.main import option_parser as lrfviewerop
    from calibre.gui2.viewer.main import option_parser as viewer_op
    from calibre.gui2.tweak_book.main import option_parser as tweak_op
    from calibre.ebooks.metadata.sources.cli import option_parser as fem_op
    from calibre.gui2.main import option_parser as guiop
    from calibre.utils.smtp import option_parser as smtp_op
    from calibre.srv.standalone import create_option_parser as serv_op
    from calibre.ebooks.oeb.polish.main import option_parser as polish_op, SUPPORTED
    from calibre.ebooks.oeb.polish.import_book import IMPORTABLE
    from calibre.debug import option_parser as debug_op
    from calibre.ebooks import BOOK_EXTENSIONS
    from calibre.customize.ui import available_input_formats
    input_formats = sorted(all_input_formats())
    tweak_formats = sorted(x.lower() for x in SUPPORTED|IMPORTABLE)

    if bash_comp_dest and not os.path.exists(os.path.dirname(bash_comp_dest)):
        os.makedirs(os.path.dirname(bash_comp_dest))

    complete = 'calibre-complete'
    if getattr(sys, 'frozen_path', None):
        complete = os.path.join(getattr(sys, 'frozen_path'), complete)

    with open(bash_comp_dest or os.devnull, 'wb') as f:
        def o_and_e(*args, **kwargs):
            f.write(opts_and_exts(*args, **kwargs))
            zsh.opts_and_exts(*args, **kwargs)

        def o_and_w(*args, **kwargs):
            f.write(opts_and_words(*args, **kwargs))
            zsh.opts_and_words(*args, **kwargs)

        f.write('# calibre Bash Shell Completion\n')
        o_and_e('calibre', guiop, BOOK_EXTENSIONS)
        o_and_e('lrf2lrs', lrf2lrsop, ['lrf'], file_map={'--output':['lrs']})
        o_and_e('ebook-meta', metaop,
                list(meta_filetypes()), cover_opts=['--cover', '-c'],
                opf_opts=['--to-opf', '--from-opf'])
        o_and_e('ebook-polish', polish_op,
                [x.lower() for x in SUPPORTED], cover_opts=['--cover', '-c'],
                opf_opts=['--opf', '-o'])
        o_and_e('lrfviewer', lrfviewerop, ['lrf'])
        o_and_e('ebook-viewer', viewer_op, input_formats)
        o_and_e('ebook-edit', tweak_op, tweak_formats)
        o_and_w('fetch-ebook-metadata', fem_op, [])
        o_and_w('calibre-smtp', smtp_op, [])
        o_and_w('calibre-server', serv_op, [])
        o_and_e('calibre-debug', debug_op, ['py', 'recipe', 'mobi', 'azw', 'azw3', 'docx'], file_map={
            '--tweak-book':['epub', 'azw3', 'mobi'],
            '--subset-font':['ttf', 'otf'],
            '--exec-file':['py', 'recipe'],
            '--add-simple-plugin':['py'],
            '--inspect-mobi':['mobi', 'azw', 'azw3'],
            '--viewer':sorted(available_input_formats()),
        })
        f.write(textwrap.dedent('''
        _ebook_device_ls()
        {
        local pattern search listing prefix
        pattern="$1"
        search="$1"
        if [[ -n "{$pattern}" ]]; then
            if [[ "${pattern:(-1)}" == "/" ]]; then
            pattern=""
            else
            pattern="$(basename ${pattern} 2> /dev/null)"
            search="$(dirname ${search} 2> /dev/null)"
            fi
        fi

        if [[  "x${search}" == "x" || "x${search}" == "x." ]]; then
            search="/"
        fi

        listing="$(ebook-device ls ${search} 2>/dev/null)"

        prefix="${search}"
        if [[ "x${prefix:(-1)}" != "x/" ]]; then
            prefix="${prefix}/"
        fi

        echo $(compgen -P "${prefix}" -W "${listing}" "${pattern}")
        }

        _ebook_device()
        {
        local cur prev
        cur="${COMP_WORDS[COMP_CWORD]}"
        prev="${COMP_WORDS[COMP_CWORD-1]}"
        COMPREPLY=()
        case "${prev}" in
            ls|rm|mkdir|touch|cat )
                COMPREPLY=( $(_ebook_device_ls "${cur}") )
                return 0
                ;;
            cp )
                if [[ ${cur} == dev:* ]]; then
                COMPREPLY=( $(_ebook_device_ls "${cur:7}") )
                return 0
                else
                _filedir
                return 0
                fi
                ;;
            dev )
                COMPREPLY=( $(compgen -W "cp ls rm mkdir touch cat info books df" "${cur}") )
                return 0
                ;;
            * )
                if [[ ${cur} == dev:* ]]; then
                COMPREPLY=( $(_ebook_device_ls "${cur:7}") )
                return 0
                else
                if [[ ${prev} == dev:* ]]; then
                    _filedir
                    return 0
                else
                    COMPREPLY=( $(compgen -W "dev:" "${cur}") )
                    return 0
                fi
                return 0
                fi
            ;;
        esac
        }
        complete -o nospace  -F _ebook_device ebook-device

        complete -o nospace -C %s ebook-convert
        ''')%complete)
    zsh.write()
Exemplo n.º 14
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()
Exemplo n.º 15
0
def supported_input_formats():
    fmts = available_input_formats()
    for x in ('zip', 'rar', 'oebzip'):
        fmts.add(x)
    return fmts
Exemplo n.º 16
0
    def setup_completion(self):  # {{{
        try:
            self.info('Setting up command-line completion...')
            from calibre.ebooks.metadata.cli import option_parser as metaop, filetypes as meta_filetypes
            from calibre.ebooks.lrf.lrfparser import option_parser as lrf2lrsop
            from calibre.gui2.lrf_renderer.main import option_parser as lrfviewerop
            from calibre.gui2.viewer.main import option_parser as viewer_op
            from calibre.gui2.tweak_book.main import option_parser as tweak_op
            from calibre.ebooks.metadata.sources.cli import option_parser as fem_op
            from calibre.gui2.main import option_parser as guiop
            from calibre.utils.smtp import option_parser as smtp_op
            from calibre.library.server.main import option_parser as serv_op
            from calibre.ebooks.oeb.polish.main import option_parser as polish_op, SUPPORTED
            from calibre.ebooks.oeb.polish.import_book import IMPORTABLE
            from calibre.debug import option_parser as debug_op
            from calibre.ebooks import BOOK_EXTENSIONS
            from calibre.customize.ui import available_input_formats
            input_formats = sorted(all_input_formats())
            tweak_formats = sorted(x.lower() for x in SUPPORTED|IMPORTABLE)
            zsh = ZshCompleter(self.opts)
            bc = os.path.join(os.path.dirname(self.opts.staging_sharedir),
                'bash-completion')
            if os.path.exists(bc):
                f = os.path.join(bc, 'calibre')
            else:
                if isnetbsd:
                    f = os.path.join(self.opts.staging_root, 'share/bash_completion.d/calibre')
                else:
                    f = os.path.join(self.opts.staging_etc, 'bash_completion.d/calibre')
            if not os.path.exists(os.path.dirname(f)):
                os.makedirs(os.path.dirname(f))
            bash_comp_dest, zsh_comp_dest = f, None
            if zsh.dest:
                self.info('Installing zsh completion to:', zsh.dest)
                self.manifest.append(zsh.dest)
                zsh_comp_dest = zsh.dest
            complete = 'calibre-complete'
            if getattr(sys, 'frozen_path', None):
                complete = os.path.join(getattr(sys, 'frozen_path'), complete)

            self.info('Installing bash completion to', f)
            with open(f, 'wb') as f:
                def o_and_e(*args, **kwargs):
                    f.write(opts_and_exts(*args, **kwargs))
                    zsh.opts_and_exts(*args, **kwargs)
                def o_and_w(*args, **kwargs):
                    f.write(opts_and_words(*args, **kwargs))
                    zsh.opts_and_words(*args, **kwargs)

                f.write('# calibre Bash Shell Completion\n')
                o_and_e('calibre', guiop, BOOK_EXTENSIONS)
                o_and_e('lrf2lrs', lrf2lrsop, ['lrf'], file_map={'--output':['lrs']})
                o_and_e('ebook-meta', metaop,
                        list(meta_filetypes()), cover_opts=['--cover', '-c'],
                        opf_opts=['--to-opf', '--from-opf'])
                o_and_e('ebook-polish', polish_op,
                        [x.lower() for x in SUPPORTED], cover_opts=['--cover', '-c'],
                        opf_opts=['--opf', '-o'])
                o_and_e('lrfviewer', lrfviewerop, ['lrf'])
                o_and_e('ebook-viewer', viewer_op, input_formats)
                o_and_e('ebook-edit', tweak_op, tweak_formats)
                o_and_w('fetch-ebook-metadata', fem_op, [])
                o_and_w('calibre-smtp', smtp_op, [])
                o_and_w('calibre-server', serv_op, [])
                o_and_e('calibre-debug', debug_op, ['py', 'recipe', 'mobi', 'azw', 'azw3', 'docx'], file_map={
                    '--tweak-book':['epub', 'azw3', 'mobi'],
                    '--subset-font':['ttf', 'otf'],
                    '--exec-file':['py', 'recipe'],
                    '--add-simple-plugin':['py'],
                    '--inspect-mobi':['mobi', 'azw', 'azw3'],
                    '--viewer':list(available_input_formats()),
                })
                f.write(textwrap.dedent('''
                _ebook_device_ls()
                {
                local pattern search listing prefix
                pattern="$1"
                search="$1"
                if [[ -n "{$pattern}" ]]; then
                    if [[ "${pattern:(-1)}" == "/" ]]; then
                    pattern=""
                    else
                    pattern="$(basename ${pattern} 2> /dev/null)"
                    search="$(dirname ${search} 2> /dev/null)"
                    fi
                fi

                if [[  "x${search}" == "x" || "x${search}" == "x." ]]; then
                    search="/"
                fi

                listing="$(ebook-device ls ${search} 2>/dev/null)"

                prefix="${search}"
                if [[ "x${prefix:(-1)}" != "x/" ]]; then
                    prefix="${prefix}/"
                fi

                echo $(compgen -P "${prefix}" -W "${listing}" "${pattern}")
                }

                _ebook_device()
                {
                local cur prev
                cur="${COMP_WORDS[COMP_CWORD]}"
                prev="${COMP_WORDS[COMP_CWORD-1]}"
                COMPREPLY=()
                case "${prev}" in
                    ls|rm|mkdir|touch|cat )
                        COMPREPLY=( $(_ebook_device_ls "${cur}") )
                        return 0
                        ;;
                    cp )
                        if [[ ${cur} == dev:* ]]; then
                        COMPREPLY=( $(_ebook_device_ls "${cur:7}") )
                        return 0
                        else
                        _filedir
                        return 0
                        fi
                        ;;
                    dev )
                        COMPREPLY=( $(compgen -W "cp ls rm mkdir touch cat info books df" "${cur}") )
                        return 0
                        ;;
                    * )
                        if [[ ${cur} == dev:* ]]; then
                        COMPREPLY=( $(_ebook_device_ls "${cur:7}") )
                        return 0
                        else
                        if [[ ${prev} == dev:* ]]; then
                            _filedir
                            return 0
                        else
                            COMPREPLY=( $(compgen -W "dev:" "${cur}") )
                            return 0
                        fi
                        return 0
                        fi
                    ;;
                esac
                }
                complete -o nospace  -F _ebook_device ebook-device

                complete -o nospace -C %s ebook-convert
                ''')%complete)
            zsh.write()
            self.manifest.extend((bash_comp_dest, zsh_comp_dest))
        except TypeError as err:
            if 'resolve_entities' in str(err):
                print 'You need python-lxml >= 2.0.5 for calibre'
                sys.exit(1)
            raise
        except EnvironmentError as e:
            if e.errno == errno.EACCES:
                self.warning('Failed to setup completion, permission denied')
        except:
            if self.opts.fatal_errors:
                raise
            self.task_failed('Setting up completion failed')
Exemplo n.º 17
0
def is_supported(path):
    ext = os.path.splitext(path)[1].replace(".", "").lower()
    ext = re.sub(r"(x{0,1})htm(l{0,1})", "html", ext)
    return ext in available_input_formats()
Exemplo n.º 18
0
    def setup_completion(self):  # {{{
        try:
            self.info('Setting up command-line completion...')
            from calibre.ebooks.metadata.cli import option_parser as metaop, filetypes as meta_filetypes
            from calibre.ebooks.lrf.lrfparser import option_parser as lrf2lrsop
            from calibre.gui2.lrf_renderer.main import option_parser as lrfviewerop
            from calibre.gui2.viewer.main import option_parser as viewer_op
            from calibre.gui2.tweak_book.main import option_parser as tweak_op
            from calibre.ebooks.metadata.sources.cli import option_parser as fem_op
            from calibre.gui2.main import option_parser as guiop
            from calibre.utils.smtp import option_parser as smtp_op
            from calibre.library.server.main import option_parser as serv_op
            from calibre.ebooks.oeb.polish.main import option_parser as polish_op, SUPPORTED
            from calibre.debug import option_parser as debug_op
            from calibre.ebooks import BOOK_EXTENSIONS
            from calibre.customize.ui import available_input_formats
            input_formats = sorted(all_input_formats())
            tweak_formats = sorted(x.lower() for x in SUPPORTED)
            zsh = ZshCompleter(self.opts)
            bc = os.path.join(os.path.dirname(self.opts.staging_sharedir),
                              'bash-completion')
            if os.path.exists(bc):
                f = os.path.join(bc, 'calibre')
            else:
                if isnetbsd:
                    f = os.path.join(self.opts.staging_root,
                                     'share/bash_completion.d/calibre')
                else:
                    f = os.path.join(self.opts.staging_etc,
                                     'bash_completion.d/calibre')
            if not os.path.exists(os.path.dirname(f)):
                os.makedirs(os.path.dirname(f))
            if zsh.dest:
                self.info('Installing zsh completion to:', zsh.dest)
                self.manifest.append(zsh.dest)
            self.manifest.append(f)
            complete = 'calibre-complete'
            if getattr(sys, 'frozen_path', None):
                complete = os.path.join(getattr(sys, 'frozen_path'), complete)

            self.info('Installing bash completion to', f)
            with open(f, 'wb') as f:

                def o_and_e(*args, **kwargs):
                    f.write(opts_and_exts(*args, **kwargs))
                    zsh.opts_and_exts(*args, **kwargs)

                def o_and_w(*args, **kwargs):
                    f.write(opts_and_words(*args, **kwargs))
                    zsh.opts_and_words(*args, **kwargs)

                f.write('# calibre Bash Shell Completion\n')
                o_and_e('calibre', guiop, BOOK_EXTENSIONS)
                o_and_e('lrf2lrs',
                        lrf2lrsop, ['lrf'],
                        file_map={'--output': ['lrs']})
                o_and_e('ebook-meta',
                        metaop,
                        list(meta_filetypes()),
                        cover_opts=['--cover', '-c'],
                        opf_opts=['--to-opf', '--from-opf'])
                o_and_e('ebook-polish',
                        polish_op, [x.lower() for x in SUPPORTED],
                        cover_opts=['--cover', '-c'],
                        opf_opts=['--opf', '-o'])
                o_and_e('lrfviewer', lrfviewerop, ['lrf'])
                o_and_e('ebook-viewer', viewer_op, input_formats)
                o_and_e('ebook-edit', tweak_op, tweak_formats)
                o_and_w('fetch-ebook-metadata', fem_op, [])
                o_and_w('calibre-smtp', smtp_op, [])
                o_and_w('calibre-server', serv_op, [])
                o_and_e('calibre-debug',
                        debug_op,
                        ['py', 'recipe', 'mobi', 'azw', 'azw3', 'docx'],
                        file_map={
                            '--tweak-book': ['epub', 'azw3', 'mobi'],
                            '--subset-font': ['ttf', 'otf'],
                            '--exec-file': ['py', 'recipe'],
                            '--add-simple-plugin': ['py'],
                            '--inspect-mobi': ['mobi', 'azw', 'azw3'],
                            '--viewer': list(available_input_formats()),
                        })
                f.write(
                    textwrap.dedent('''
                _ebook_device_ls()
                {
                local pattern search listing prefix
                pattern="$1"
                search="$1"
                if [[ -n "{$pattern}" ]]; then
                    if [[ "${pattern:(-1)}" == "/" ]]; then
                    pattern=""
                    else
                    pattern="$(basename ${pattern} 2> /dev/null)"
                    search="$(dirname ${search} 2> /dev/null)"
                    fi
                fi

                if [[  "x${search}" == "x" || "x${search}" == "x." ]]; then
                    search="/"
                fi

                listing="$(ebook-device ls ${search} 2>/dev/null)"

                prefix="${search}"
                if [[ "x${prefix:(-1)}" != "x/" ]]; then
                    prefix="${prefix}/"
                fi

                echo $(compgen -P "${prefix}" -W "${listing}" "${pattern}")
                }

                _ebook_device()
                {
                local cur prev
                cur="${COMP_WORDS[COMP_CWORD]}"
                prev="${COMP_WORDS[COMP_CWORD-1]}"
                COMPREPLY=()
                case "${prev}" in
                    ls|rm|mkdir|touch|cat )
                        COMPREPLY=( $(_ebook_device_ls "${cur}") )
                        return 0
                        ;;
                    cp )
                        if [[ ${cur} == dev:* ]]; then
                        COMPREPLY=( $(_ebook_device_ls "${cur:7}") )
                        return 0
                        else
                        _filedir
                        return 0
                        fi
                        ;;
                    dev )
                        COMPREPLY=( $(compgen -W "cp ls rm mkdir touch cat info books df" "${cur}") )
                        return 0
                        ;;
                    * )
                        if [[ ${cur} == dev:* ]]; then
                        COMPREPLY=( $(_ebook_device_ls "${cur:7}") )
                        return 0
                        else
                        if [[ ${prev} == dev:* ]]; then
                            _filedir
                            return 0
                        else
                            COMPREPLY=( $(compgen -W "dev:" "${cur}") )
                            return 0
                        fi
                        return 0
                        fi
                    ;;
                esac
                }
                complete -o nospace  -F _ebook_device ebook-device

                complete -o nospace -C %s ebook-convert
                ''') % complete)
            zsh.write()
        except TypeError as err:
            if 'resolve_entities' in str(err):
                print 'You need python-lxml >= 2.0.5 for calibre'
                sys.exit(1)
            raise
        except:
            if self.opts.fatal_errors:
                raise
            self.task_failed('Setting up completion failed')
Exemplo n.º 19
0
def write_completion(bash_comp_dest, zsh):
    from calibre.ebooks.metadata.cli import option_parser as metaop, filetypes as meta_filetypes
    from calibre.ebooks.lrf.lrfparser import option_parser as lrf2lrsop
    from calibre.gui2.lrf_renderer.main import option_parser as lrfviewerop
    from calibre.gui2.viewer.main import option_parser as viewer_op
    from calibre.gui2.tweak_book.main import option_parser as tweak_op
    from calibre.ebooks.metadata.sources.cli import option_parser as fem_op
    from calibre.gui2.main import option_parser as guiop
    from calibre.utils.smtp import option_parser as smtp_op
    from calibre.srv.standalone import create_option_parser as serv_op
    from calibre.ebooks.oeb.polish.main import option_parser as polish_op, SUPPORTED
    from calibre.ebooks.oeb.polish.import_book import IMPORTABLE
    from calibre.debug import option_parser as debug_op
    from calibre.ebooks import BOOK_EXTENSIONS
    from calibre.customize.ui import available_input_formats
    input_formats = sorted(all_input_formats())
    tweak_formats = sorted(x.lower() for x in SUPPORTED | IMPORTABLE)

    if bash_comp_dest and not os.path.exists(os.path.dirname(bash_comp_dest)):
        os.makedirs(os.path.dirname(bash_comp_dest))

    complete = 'calibre-complete'
    if getattr(sys, 'frozen_path', None):
        complete = os.path.join(getattr(sys, 'frozen_path'), complete)

    with open(bash_comp_dest or os.devnull, 'wb') as f:
        w = polyglot_write(f)

        def o_and_e(*args, **kwargs):
            w(opts_and_exts(*args, **kwargs))
            zsh.opts_and_exts(*args, **kwargs)

        def o_and_w(*args, **kwargs):
            w(opts_and_words(*args, **kwargs))
            zsh.opts_and_words(*args, **kwargs)

        w('# calibre Bash Shell Completion\n')
        o_and_e('calibre', guiop, BOOK_EXTENSIONS)
        o_and_e('lrf2lrs', lrf2lrsop, ['lrf'], file_map={'--output': ['lrs']})
        o_and_e('ebook-meta',
                metaop,
                list(meta_filetypes()),
                cover_opts=['--cover', '-c'],
                opf_opts=['--to-opf', '--from-opf'])
        o_and_e('ebook-polish',
                polish_op, [x.lower() for x in SUPPORTED],
                cover_opts=['--cover', '-c'],
                opf_opts=['--opf', '-o'])
        o_and_e('lrfviewer', lrfviewerop, ['lrf'])
        o_and_e('ebook-viewer', viewer_op, input_formats)
        o_and_e('ebook-edit', tweak_op, tweak_formats)
        o_and_w('fetch-ebook-metadata', fem_op, [])
        o_and_w('calibre-smtp', smtp_op, [])
        o_and_w('calibre-server', serv_op, [])
        o_and_e('calibre-debug',
                debug_op, ['py', 'recipe', 'mobi', 'azw', 'azw3', 'docx'],
                file_map={
                    '--tweak-book': ['epub', 'azw3', 'mobi'],
                    '--subset-font': ['ttf', 'otf'],
                    '--exec-file': ['py', 'recipe'],
                    '--add-simple-plugin': ['py'],
                    '--inspect-mobi': ['mobi', 'azw', 'azw3'],
                    '--viewer': sorted(available_input_formats()),
                })
        w(
            textwrap.dedent('''
        _ebook_device_ls()
        {
        local pattern search listing prefix
        pattern="$1"
        search="$1"
        if [[ -n "{$pattern}" ]]; then
            if [[ "${pattern:(-1)}" == "/" ]]; then
            pattern=""
            else
            pattern="$(basename ${pattern} 2> /dev/null)"
            search="$(dirname ${search} 2> /dev/null)"
            fi
        fi

        if [[  "x${search}" == "x" || "x${search}" == "x." ]]; then
            search="/"
        fi

        listing="$(ebook-device ls ${search} 2>/dev/null)"

        prefix="${search}"
        if [[ "x${prefix:(-1)}" != "x/" ]]; then
            prefix="${prefix}/"
        fi

        echo $(compgen -P "${prefix}" -W "${listing}" "${pattern}")
        }

        _ebook_device()
        {
        local cur prev
        cur="${COMP_WORDS[COMP_CWORD]}"
        prev="${COMP_WORDS[COMP_CWORD-1]}"
        COMPREPLY=()
        case "${prev}" in
            ls|rm|mkdir|touch|cat )
                COMPREPLY=( $(_ebook_device_ls "${cur}") )
                return 0
                ;;
            cp )
                if [[ ${cur} == dev:* ]]; then
                COMPREPLY=( $(_ebook_device_ls "${cur:7}") )
                return 0
                else
                _filedir
                return 0
                fi
                ;;
            dev )
                COMPREPLY=( $(compgen -W "cp ls rm mkdir touch cat info books df" "${cur}") )
                return 0
                ;;
            * )
                if [[ ${cur} == dev:* ]]; then
                COMPREPLY=( $(_ebook_device_ls "${cur:7}") )
                return 0
                else
                if [[ ${prev} == dev:* ]]; then
                    _filedir
                    return 0
                else
                    COMPREPLY=( $(compgen -W "dev:" "${cur}") )
                    return 0
                fi
                return 0
                fi
            ;;
        esac
        }
        complete -o nospace  -F _ebook_device ebook-device

        complete -o nospace -C %s ebook-convert
        ''') % complete)
    zsh.write()
Exemplo n.º 20
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_()
Exemplo n.º 21
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_()
Exemplo n.º 22
0
def write_completion(bash_comp_dest, zsh):
    from calibre.ebooks.metadata.cli import option_parser as metaop, filetypes as meta_filetypes
    from calibre.ebooks.lrf.lrfparser import option_parser as lrf2lrsop
    from calibre.gui2.lrf_renderer.main import option_parser as lrfviewerop
    from calibre.gui2.viewer.main import option_parser as viewer_op
    from calibre.gui2.tweak_book.main import option_parser as tweak_op
    from calibre.ebooks.metadata.sources.cli import option_parser as fem_op
    from calibre.gui2.main import option_parser as guiop
    from calibre.utils.smtp import option_parser as smtp_op
    from calibre.library.server.main import option_parser as serv_op
    from calibre.ebooks.oeb.polish.main import option_parser as polish_op, SUPPORTED
    from calibre.ebooks.oeb.polish.import_book import IMPORTABLE
    from calibre.debug import option_parser as debug_op
    from calibre.ebooks import BOOK_EXTENSIONS
    from calibre.customize.ui import available_input_formats

    input_formats = sorted(all_input_formats())
    tweak_formats = sorted(x.lower() for x in SUPPORTED | IMPORTABLE)

    if bash_comp_dest and not os.path.exists(os.path.dirname(bash_comp_dest)):
        os.makedirs(os.path.dirname(bash_comp_dest))

    complete = "calibre-complete"
    if getattr(sys, "frozen_path", None):
        complete = os.path.join(getattr(sys, "frozen_path"), complete)

    with open(bash_comp_dest or os.devnull, "wb") as f:

        def o_and_e(*args, **kwargs):
            f.write(opts_and_exts(*args, **kwargs))
            zsh.opts_and_exts(*args, **kwargs)

        def o_and_w(*args, **kwargs):
            f.write(opts_and_words(*args, **kwargs))
            zsh.opts_and_words(*args, **kwargs)

        f.write("# calibre Bash Shell Completion\n")
        o_and_e("calibre", guiop, BOOK_EXTENSIONS)
        o_and_e("lrf2lrs", lrf2lrsop, ["lrf"], file_map={"--output": ["lrs"]})
        o_and_e(
            "ebook-meta",
            metaop,
            list(meta_filetypes()),
            cover_opts=["--cover", "-c"],
            opf_opts=["--to-opf", "--from-opf"],
        )
        o_and_e(
            "ebook-polish",
            polish_op,
            [x.lower() for x in SUPPORTED],
            cover_opts=["--cover", "-c"],
            opf_opts=["--opf", "-o"],
        )
        o_and_e("lrfviewer", lrfviewerop, ["lrf"])
        o_and_e("ebook-viewer", viewer_op, input_formats)
        o_and_e("ebook-edit", tweak_op, tweak_formats)
        o_and_w("fetch-ebook-metadata", fem_op, [])
        o_and_w("calibre-smtp", smtp_op, [])
        o_and_w("calibre-server", serv_op, [])
        o_and_e(
            "calibre-debug",
            debug_op,
            ["py", "recipe", "mobi", "azw", "azw3", "docx"],
            file_map={
                "--tweak-book": ["epub", "azw3", "mobi"],
                "--subset-font": ["ttf", "otf"],
                "--exec-file": ["py", "recipe"],
                "--add-simple-plugin": ["py"],
                "--inspect-mobi": ["mobi", "azw", "azw3"],
                "--viewer": list(available_input_formats()),
            },
        )
        f.write(
            textwrap.dedent(
                """
        _ebook_device_ls()
        {
        local pattern search listing prefix
        pattern="$1"
        search="$1"
        if [[ -n "{$pattern}" ]]; then
            if [[ "${pattern:(-1)}" == "/" ]]; then
            pattern=""
            else
            pattern="$(basename ${pattern} 2> /dev/null)"
            search="$(dirname ${search} 2> /dev/null)"
            fi
        fi

        if [[  "x${search}" == "x" || "x${search}" == "x." ]]; then
            search="/"
        fi

        listing="$(ebook-device ls ${search} 2>/dev/null)"

        prefix="${search}"
        if [[ "x${prefix:(-1)}" != "x/" ]]; then
            prefix="${prefix}/"
        fi

        echo $(compgen -P "${prefix}" -W "${listing}" "${pattern}")
        }

        _ebook_device()
        {
        local cur prev
        cur="${COMP_WORDS[COMP_CWORD]}"
        prev="${COMP_WORDS[COMP_CWORD-1]}"
        COMPREPLY=()
        case "${prev}" in
            ls|rm|mkdir|touch|cat )
                COMPREPLY=( $(_ebook_device_ls "${cur}") )
                return 0
                ;;
            cp )
                if [[ ${cur} == dev:* ]]; then
                COMPREPLY=( $(_ebook_device_ls "${cur:7}") )
                return 0
                else
                _filedir
                return 0
                fi
                ;;
            dev )
                COMPREPLY=( $(compgen -W "cp ls rm mkdir touch cat info books df" "${cur}") )
                return 0
                ;;
            * )
                if [[ ${cur} == dev:* ]]; then
                COMPREPLY=( $(_ebook_device_ls "${cur:7}") )
                return 0
                else
                if [[ ${prev} == dev:* ]]; then
                    _filedir
                    return 0
                else
                    COMPREPLY=( $(compgen -W "dev:" "${cur}") )
                    return 0
                fi
                return 0
                fi
            ;;
        esac
        }
        complete -o nospace  -F _ebook_device ebook-device

        complete -o nospace -C %s ebook-convert
        """
            )
            % complete
        )
    zsh.write()
Exemplo n.º 23
0
def is_supported(path):
    ext = os.path.splitext(path)[1].replace('.', '').lower()
    ext = re.sub(r'(x{0,1})htm(l{0,1})', 'html', ext)
    return ext in available_input_formats() or ext == 'kepub'
Exemplo n.º 24
0
def interface_data(ctx, rd):
    '''
    Return the data needed to create the server main UI

    Optional: ?num=50&sort=timestamp.desc&library_id=<default library>
              &search=''&extra_books=''
    '''
    ans = {
        'username':
        rd.username,
        'output_format':
        prefs['output_format'].upper(),
        'input_formats': {x.upper(): True
                          for x in available_input_formats()},
        'gui_pubdate_display_format':
        tweaks['gui_pubdate_display_format'],
        'gui_timestamp_display_format':
        tweaks['gui_timestamp_display_format'],
        'gui_last_modified_display_format':
        tweaks['gui_last_modified_display_format'],
        'use_roman_numerals_for_series_number':
        get_use_roman(),
        'translations':
        get_translations(),
    }
    ans['library_map'], ans['default_library'] = ctx.library_info(rd)
    ud = {}
    if rd.username:
        # Override session data with stored values for the authenticated user,
        # if any
        ud = ctx.user_manager.get_session_data(rd.username)
        lid = ud.get('library_id')
        if lid and lid in ans['library_map']:
            rd.query.set('library_id', lid)
        usort = ud.get('sort')
        if usort:
            rd.query.set('sort', usort)
    ans['library_id'], db, sorts, orders = get_basic_query_data(ctx, rd)
    ans['user_session_data'] = ud
    try:
        num = int(rd.query.get('num', DEFAULT_NUMBER_OF_BOOKS))
    except Exception:
        raise HTTPNotFound('Invalid number of books: %r' % rd.query.get('num'))
    with db.safe_read_lock:
        try:
            ans['search_result'] = search_result(ctx, rd, db,
                                                 rd.query.get('search', ''),
                                                 num, 0, ','.join(sorts),
                                                 ','.join(orders))
        except ParseException:
            ans['search_result'] = search_result(ctx, rd, db, '', num, 0,
                                                 ','.join(sorts),
                                                 ','.join(orders))
        sf = db.field_metadata.ui_sortable_field_keys()
        sf.pop('ondevice', None)
        ans['sortable_fields'] = sorted(
            ((sanitize_sort_field_name(db.field_metadata, k), v)
             for k, v in sf.iteritems()),
            key=lambda (field, name): sort_key(name))
        ans['field_metadata'] = db.field_metadata.all_metadata()
        ans['icon_map'] = icon_map()
        ans['icon_path'] = ctx.url_for('/icon', which='')
        mdata = ans['metadata'] = {}
        try:
            extra_books = set(
                int(x) for x in rd.query.get('extra_books', '').split(','))
        except Exception:
            extra_books = ()
        for coll in (ans['search_result']['book_ids'], extra_books):
            for book_id in coll:
                if book_id not in mdata:
                    data = book_as_json(db, book_id)
                    if data is not None:
                        mdata[book_id] = data

    return ans
Exemplo n.º 25
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 == 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_()
Exemplo n.º 26
0
def interface_data(ctx, rd):
    """
    Return the data needed to create the server main UI

    Optional: ?num=50&sort=timestamp.desc&library_id=<default library>
              &search=''&extra_books=''
    """
    ans = {
        "username": rd.username,
        "output_format": prefs["output_format"].upper(),
        "input_formats": {x.upper(): True for x in available_input_formats()},
        "gui_pubdate_display_format": tweaks["gui_pubdate_display_format"],
        "gui_timestamp_display_format": tweaks["gui_timestamp_display_format"],
        "gui_last_modified_display_format": tweaks["gui_last_modified_display_format"],
        "use_roman_numerals_for_series_number": get_use_roman(),
    }
    ans["library_map"], ans["default_library"] = ctx.library_map
    ud = {}
    if rd.username:
        # Override session data with stored values for the authenticated user,
        # if any
        ud = ctx.user_manager.get_session_data(rd.username)
        lid = ud.get("library_id")
        if lid and lid in ans["library_map"]:
            rd.query.set("library_id", lid)
        usort = ud.get("sort")
        if usort:
            rd.query.set("sort", usort)
    ans["library_id"], db, sorts, orders = get_basic_query_data(ctx, rd.query)
    ans["user_session_data"] = ud
    try:
        num = int(rd.query.get("num", DEFAULT_NUMBER_OF_BOOKS))
    except Exception:
        raise HTTPNotFound("Invalid number of books: %r" % rd.query.get("num"))
    with db.safe_read_lock:
        try:
            ans["search_result"] = search_result(
                ctx, rd, db, rd.query.get("search", ""), num, 0, ",".join(sorts), ",".join(orders)
            )
        except ParseException:
            ans["search_result"] = search_result(ctx, rd, db, "", num, 0, ",".join(sorts), ",".join(orders))
        sf = db.field_metadata.ui_sortable_field_keys()
        sf.pop("ondevice", None)
        ans["sortable_fields"] = sorted(
            ((sanitize_sort_field_name(db.field_metadata, k), v) for k, v in sf.iteritems()),
            key=lambda (field, name): sort_key(name),
        )
        ans["field_metadata"] = db.field_metadata.all_metadata()
        ans["icon_map"] = icon_map()
        ans["icon_path"] = ctx.url_for("/icon", which="")
        mdata = ans["metadata"] = {}
        try:
            extra_books = set(int(x) for x in rd.query.get("extra_books", "").split(","))
        except Exception:
            extra_books = ()
        for coll in (ans["search_result"]["book_ids"], extra_books):
            for book_id in coll:
                if book_id not in mdata:
                    data = book_as_json(db, book_id)
                    if data is not None:
                        mdata[book_id] = data

    return ans