Exemple #1
0
def compress_images(container,
                    report=None,
                    names=None,
                    jpeg_quality=None,
                    progress_callback=lambda n, t, name: True):
    images = get_compressible_images(container)
    if names is not None:
        images &= set(names)
    results = {}
    queue = Queue()
    abort = Event()
    for name in images:
        queue.put(name)

    def pc(name):
        keep_going = progress_callback(len(results), len(images), name)
        if not keep_going:
            abort.set()

    progress_callback(0, len(images), '')
    [
        Worker(abort, 'CompressImage%d' % i, queue, results, container,
               jpeg_quality, pc)
        for i in range(min(detect_ncpus(), len(images)))
    ]
    queue.join()
    before_total = after_total = 0
    changed = False
    for name, (ok, res) in results.iteritems():
        name = force_unicode(name, filesystem_encoding)
        if ok:
            before, after = res
            if before != after:
                changed = True
            before_total += before
            after_total += after
            if report:
                if before != after:
                    report(
                        _('{0} compressed from {1} to {2} bytes [{3:.1%} reduction]'
                          ).format(name, human_readable(before),
                                   human_readable(after),
                                   (before - after) / before))
                else:
                    report(
                        _('{0} could not be further compressed').format(name))
        else:
            report(_('Failed to process {0} with error:').format(name))
            report(res)
    if report:
        if changed:
            report('')
            report(
                _('Total image filesize reduced from {0} to {1} [{2:.1%} reduction]'
                  ).format(human_readable(before_total),
                           human_readable(after_total),
                           (before_total - after_total) / before_total))
        else:
            report(_('Images are already fully optimized'))
    return changed, results
 def paint(self, painter, option, index):
     top_level = not index.parent().isValid()
     hover = option.state & QStyle.State_MouseOver
     if hover:
         if top_level:
             suffix = '%s(%d)' % (NBSP, index.model().rowCount(index))
         else:
             try:
                 suffix = NBSP + human_readable(
                     current_container().filesize(
                         unicode(index.data(NAME_ROLE).toString())))
             except EnvironmentError:
                 suffix = NBSP + human_readable(0)
         br = painter.boundingRect(option.rect,
                                   Qt.AlignRight | Qt.AlignVCenter, suffix)
     if top_level and index.row() > 0:
         option.rect.adjust(0, 5, 0, 0)
         painter.drawLine(option.rect.topLeft(), option.rect.topRight())
         option.rect.adjust(0, 1, 0, 0)
     if hover:
         option.rect.adjust(0, 0, -br.width(), 0)
     QStyledItemDelegate.paint(self, painter, option, index)
     if hover:
         option.rect.adjust(0, 0, br.width(), 0)
         painter.drawText(option.rect, Qt.AlignRight | Qt.AlignVCenter,
                          suffix)
Exemple #3
0
    def paint(self, painter, option, index):
        top_level = not index.parent().isValid()
        hover = option.state & QStyle.StateFlag.State_MouseOver
        cc = current_container()

        def safe_size(index):
            try:
                return cc.filesize(str(index.data(NAME_ROLE) or ''))
            except OSError:
                return 0

        if hover:
            if top_level:
                count = index.model().rowCount(index)
                total_size = human_readable(sum(safe_size(index.child(r, 0)) for r in range(count)))
                suffix = f'{NBSP}{count}@{total_size}'
            else:
                suffix = NBSP + human_readable(safe_size(index))
            br = painter.boundingRect(option.rect, Qt.AlignmentFlag.AlignRight|Qt.AlignmentFlag.AlignVCenter, suffix)
        if top_level and index.row() > 0:
            option.rect.adjust(0, 5, 0, 0)
            painter.drawLine(option.rect.topLeft(), option.rect.topRight())
            option.rect.adjust(0, 1, 0, 0)
        if hover:
            option.rect.adjust(0, 0, -br.width(), 0)
        QStyledItemDelegate.paint(self, painter, option, index)
        if hover:
            option.rect.adjust(0, 0, br.width(), 0)
            painter.drawText(option.rect, Qt.AlignmentFlag.AlignRight|Qt.AlignmentFlag.AlignVCenter, suffix)
Exemple #4
0
def compress_images(container, report=None, names=None, jpeg_quality=None, progress_callback=lambda n, t, name:True):
    images = get_compressible_images(container)
    if names is not None:
        images &= set(names)
    results = {}
    queue = Queue()
    abort = Event()
    seen = set()
    num_to_process = 0
    for name in sorted(images):
        path = os.path.abspath(container.get_file_path_for_processing(name))
        path_key = os.path.normcase(path)
        if path_key not in seen:
            num_to_process += 1
            queue.put((name, path, container.mime_map[name]))
            seen.add(path_key)

    def pc(name):
        keep_going = progress_callback(len(results), num_to_process, name)
        if not keep_going:
            abort.set()
    progress_callback(0, num_to_process, '')
    [Worker(abort, 'CompressImage%d' % i, queue, results, jpeg_quality, pc) for i in range(min(detect_ncpus(), num_to_process))]
    queue.join()
    before_total = after_total = 0
    processed_num = 0
    changed = False
    for name, (ok, res) in iteritems(results):
        name = force_unicode(name, filesystem_encoding)
        if ok:
            before, after = res
            if before != after:
                changed = True
                processed_num += 1
            before_total += before
            after_total += after
            if report:
                if before != after:
                    report(_('{0} compressed from {1} to {2} bytes [{3:.1%} reduction]').format(
                        name, human_readable(before), human_readable(after), (before - after)/before))
                else:
                    report(_('{0} could not be further compressed').format(name))
        else:
            report(_('Failed to process {0} with error:').format(name))
            report(res)
    if report:
        if changed:
            report('')
            report(_('Total image filesize reduced from {0} to {1} [{2:.1%} reduction, {3} images changed]').format(
                human_readable(before_total), human_readable(after_total), (before_total - after_total)/before_total, processed_num))
        else:
            report(_('Images are already fully optimized'))
    return changed, results
Exemple #5
0
    def add_diff(self,
                 left_name,
                 right_name,
                 left_text,
                 right_text,
                 context=None,
                 syntax=None,
                 beautify=False):
        left_text, right_text = left_text or '', right_text or ''
        is_identical = len(left_text) == len(
            right_text) and left_text == right_text and left_name == right_name
        is_text = isinstance(left_text, type('')) and isinstance(
            right_text, type(''))
        left_name = left_name or '[%s]' % _('This file was added')
        right_name = right_name or '[%s]' % _('This file was removed')
        self.left.headers.append((self.left.blockCount() - 1, left_name))
        self.right.headers.append((self.right.blockCount() - 1, right_name))
        for v in (self.left, self.right):
            c = v.textCursor()
            c.movePosition(c.End)
            (c.insertBlock(), c.insertBlock(), c.insertBlock())

        with BusyCursor():
            if is_identical:
                for v in (self.left, self.right):
                    c = v.textCursor()
                    c.movePosition(c.End)
                    c.insertText('[%s]\n\n' % _('The files are identical'))
            elif left_name != right_name and not left_text and not right_text:
                self.add_text_diff(
                    _('[This file was renamed to %s]') % right_name,
                    _('[This file was renamed from %s]') % left_name, context,
                    None)
                for v in (self.left, self.right):
                    v.appendPlainText('\n')
            elif is_text:
                self.add_text_diff(left_text,
                                   right_text,
                                   context,
                                   syntax,
                                   beautify=beautify)
            elif syntax == 'raster_image':
                self.add_image_diff(left_text, right_text)
            else:
                text = '[%s]' % _('Binary file of size: %s')
                left_text, right_text = text % human_readable(
                    len(left_text)), text % human_readable(len(right_text))
                self.add_text_diff(left_text, right_text, None, None)
                for v in (self.left, self.right):
                    v.appendPlainText('\n')
Exemple #6
0
    def add_diff(self, left_name, right_name, left_text, right_text, context=None, syntax=None, beautify=False):
        left_text, right_text = left_text or '', right_text or ''
        is_identical = len(left_text) == len(right_text) and left_text == right_text and left_name == right_name
        is_text = isinstance(left_text, type('')) and isinstance(right_text, type(''))
        left_name = left_name or '[%s]'%_('This file was added')
        right_name = right_name or '[%s]'%_('This file was removed')
        self.left.headers.append((self.left.blockCount() - 1, left_name))
        self.right.headers.append((self.right.blockCount() - 1, right_name))
        for v in (self.left, self.right):
            c = v.textCursor()
            c.movePosition(c.End)
            (c.insertBlock(), c.insertBlock(), c.insertBlock())

        with BusyCursor():
            if is_identical:
                for v in (self.left, self.right):
                    c = v.textCursor()
                    c.movePosition(c.End)
                    c.insertText('[%s]\n\n' % _('The files are identical'))
            elif left_name != right_name and not left_text and not right_text:
                self.add_text_diff(_('[This file was renamed to %s]') % right_name, _('[This file was renamed from %s]') % left_name, context, None)
                for v in (self.left, self.right):
                    v.appendPlainText('\n')
            elif is_text:
                self.add_text_diff(left_text, right_text, context, syntax, beautify=beautify)
            elif syntax == 'raster_image':
                self.add_image_diff(left_text, right_text)
            else:
                text = '[%s]' % _('Binary file of size: %s')
                left_text, right_text = text % human_readable(len(left_text)), text % human_readable(len(right_text))
                self.add_text_diff(left_text, right_text, None, None)
                for v in (self.left, self.right):
                    v.appendPlainText('\n')
Exemple #7
0
 def paint(self, painter, option, index):
     name = index.data(Qt.ItemDataRole.DisplayRole)
     sz = human_readable(index.data(Qt.ItemDataRole.UserRole))
     pmap = index.data(Qt.ItemDataRole.UserRole + 1)
     irect = option.rect.adjusted(0, 5, 0, -5)
     irect.setRight(irect.left() + 70)
     if pmap is None:
         pmap = QPixmap(
             current_container().get_file_path_for_processing(name))
         scaled, nwidth, nheight = fit_image(pmap.width(), pmap.height(),
                                             irect.width(), irect.height())
         if scaled:
             pmap = pmap.scaled(
                 nwidth,
                 nheight,
                 transformMode=Qt.TransformationMode.SmoothTransformation)
         index.model().setData(index, pmap, Qt.ItemDataRole.UserRole + 1)
     x, y = (irect.width() - pmap.width()) // 2, (irect.height() -
                                                  pmap.height()) // 2
     r = irect.adjusted(x, y, -x, -y)
     QStyledItemDelegate.paint(self, painter, option, empty_index)
     painter.drawPixmap(r, pmap)
     trect = irect.adjusted(irect.width() + 10, 0, 0, 0)
     trect.setRight(option.rect.right())
     painter.save()
     if option.state & QStyle.StateFlag.State_Selected:
         painter.setPen(
             QPen(option.palette.color(QPalette.ColorRole.HighlightedText)))
     painter.drawText(
         trect, Qt.AlignmentFlag.AlignVCenter | Qt.AlignmentFlag.AlignLeft,
         name + '\n' + sz)
     painter.restore()
Exemple #8
0
 def paint(self, painter, option, index):
     QStyledItemDelegate.paint(self, painter, option, QModelIndex())
     theme = index.data(Qt.UserRole)
     if not theme:
         return
     painter.save()
     pixmap = index.data(Qt.DecorationRole)
     if pixmap and not pixmap.isNull():
         rect = option.rect.adjusted(0, self.SPACING, COVER_SIZE[0] - option.rect.width(), - self.SPACING)
         painter.drawPixmap(rect, pixmap)
     if option.state & QStyle.State_Selected:
         painter.setPen(QPen(QApplication.instance().palette().highlightedText().color()))
     bottom = option.rect.bottom() - 2
     painter.drawLine(0, bottom, option.rect.right(), bottom)
     if 'static-text' not in theme:
         theme['static-text'] = QStaticText(_(
             '''
         <h1>{title}</h1>
         <p>by <i>{author}</i> with <b>{number}</b> icons [{size}]</p>
         <p>{description}</p>
         <p>Version: {version} Number of users: {usage}</p>
         '''.format(title=theme.get('title', _('Unknown')), author=theme.get('author', _('Unknown')),
                    number=theme.get('number', 0), description=theme.get('description', ''),
                    size=human_readable(theme.get('compressed-size', 0)), version=theme.get('version', 1),
                    usage=theme.get('usage', 0),
     )))
     painter.drawStaticText(COVER_SIZE[0] + self.SPACING, option.rect.top() + self.SPACING, theme['static-text'])
     painter.restore()
Exemple #9
0
 def add_image_diff(self, left_data, right_data):
     def load(data):
         p = QPixmap()
         p.loadFromData(bytes(data))
         if data and p.isNull():
             p = self.failed_img
         return p
     left_img, right_img = load(left_data), load(right_data)
     change = []
     # Let any initial resizing of the window finish in case this is the
     # first diff, to avoid the expensive resize calculation later
     QApplication.processEvents(QEventLoop.ExcludeUserInputEvents | QEventLoop.ExcludeSocketNotifiers)
     for v, img, size in ((self.left, left_img, len(left_data)), (self.right, right_img, len(right_data))):
         c = v.textCursor()
         c.movePosition(c.End)
         start = c.block().blockNumber()
         lines, w = self.get_lines_for_image(img, v)
         c.movePosition(c.StartOfBlock)
         if size > 0:
             c.beginEditBlock()
             c.insertText(_('Size: {0} Resolution: {1}x{2}').format(human_readable(size), img.width(), img.height()))
             for i in xrange(lines + 1):
                 c.insertBlock()
         change.extend((start, c.block().blockNumber()))
         c.insertBlock()
         c.endEditBlock()
         v.images[start] = (img, w, lines)
     change.append('replace' if left_data and right_data else 'delete' if left_data else 'insert')
     self.left.changes.append((change[0], change[1], change[-1]))
     self.right.changes.append((change[2], change[3], change[-1]))
     QApplication.processEvents(QEventLoop.ExcludeUserInputEvents | QEventLoop.ExcludeSocketNotifiers)
Exemple #10
0
 def current_image_changed(self):
     self.info_label.setText('')
     name = self.file_name
     if name is not None:
         data = self.container.raw_data(name, decode=False)
         self.cover_view.set_pixmap(data)
         self.info_label.setText('{0}x{1}px | {2}'.format(
             self.cover_view.pixmap.width(), self.cover_view.pixmap.height(), human_readable(len(data))))
Exemple #11
0
 def update_tooltips(self):
     for i, loc in enumerate(('main', 'carda', 'cardb')):
         t = self.tooltips[loc]
         if self.free[i] > -1:
             t += u'\n\n%s '%human_readable(self.free[i]) + _('available')
         ac = getattr(self, 'location_'+loc)
         ac.setToolTip(t)
         ac.setWhatsThis(t)
         ac.setStatusTip(t)
Exemple #12
0
def subset_fonts(pdf_doc, log):
    all_fonts = pdf_doc.list_fonts(True)
    for font in all_fonts:
        if font['Subtype'] != 'Type0' and font['Data']:
            try:
                sfnt = Sfnt(font['Data'])
            except UnsupportedFont:
                continue
            if b'glyf' not in sfnt:
                continue
            num, gen = font['Reference']
            glyphs = all_glyph_ids_in_w_arrays(
                (font['W'] or (), font['W2'] or ()), as_set=True)
            pdf_subset(sfnt, glyphs)
            data = sfnt()[0]
            log('Subset embedded font from: {} to {}'.format(
                human_readable(len(font['Data'])), human_readable(len(data))))
            pdf_doc.replace_font_data(data, num, gen)
Exemple #13
0
 def update_tooltips(self):
     for i, loc in enumerate(('main', 'carda', 'cardb')):
         t = self.tooltips[loc]
         if self.free[i] > -1:
             t += u'\n\n%s ' % human_readable(self.free[i]) + _('available')
         ac = getattr(self, 'location_' + loc)
         ac.setToolTip(t)
         ac.setWhatsThis(t)
         ac.setStatusTip(t)
Exemple #14
0
def compress_images(container, report=None, names=None, jpeg_quality=None, progress_callback=lambda n, t, name:True):
    images = get_compressible_images(container)
    if names is not None:
        images &= set(names)
    results = {}
    queue = Queue()
    abort = Event()
    for name in images:
        queue.put(name)

    def pc(name):
        keep_going = progress_callback(len(results), len(images), name)
        if not keep_going:
            abort.set()
    progress_callback(0, len(images), '')
    [Worker(abort, 'CompressImage%d' % i, queue, results, container, jpeg_quality, pc) for i in range(min(detect_ncpus(), len(images)))]
    queue.join()
    before_total = after_total = 0
    changed = False
    for name, (ok, res) in iteritems(results):
        name = force_unicode(name, filesystem_encoding)
        if ok:
            before, after = res
            if before != after:
                changed = True
            before_total += before
            after_total += after
            if report:
                if before != after:
                    report(_('{0} compressed from {1} to {2} bytes [{3:.1%} reduction]').format(
                        name, human_readable(before), human_readable(after), (before - after)/before))
                else:
                    report(_('{0} could not be further compressed').format(name))
        else:
            report(_('Failed to process {0} with error:').format(name))
            report(res)
    if report:
        if changed:
            report('')
            report(_('Total image filesize reduced from {0} to {1} [{2:.1%} reduction]').format(
                human_readable(before_total), human_readable(after_total), (before_total - after_total)/before_total))
        else:
            report(_('Images are already fully optimized'))
    return changed, results
Exemple #15
0
 def dump(self, prefix='', out=sys.stdout):
     c = '+' if self.is_folder else '-'
     data = ('%s children'%(sum(map(len, (self.files, self.folders))))
         if self.is_folder else human_readable(self.size))
     data += ' modified=%s'%self.last_mod_string
     line = '%s%s %s [id:%s %s]'%(prefix, c, self.name, self.object_id, data)
     prints(line, file=out)
     for c in (self.folders, self.files):
         for e in sorted(c, key=lambda x:sort_key(x.name)):
             e.dump(prefix=prefix+'  ', out=out)
Exemple #16
0
 def dump(self, prefix='', out=sys.stdout):
     c = '+' if self.is_folder else '-'
     data = ('%s children'%(sum(map(len, (self.files, self.folders))))
         if self.is_folder else human_readable(self.size))
     data += ' modified=%s'%self.last_mod_string
     line = '%s%s %s [id:%s %s]'%(prefix, c, self.name, self.object_id, data)
     prints(line, file=out)
     for c in (self.folders, self.files):
         for e in sorted(c, key=lambda x:sort_key(x.name)):
             e.dump(prefix=prefix+'  ', out=out)
Exemple #17
0
class TooLarge(BaseError):

    level = INFO
    MAX_SIZE = 260 * 1024
    HELP = _(
        'This HTML file is larger than %s. Too large HTML files can cause performance problems'
        ' on some e-book readers. Consider splitting this file into smaller sections.'
    ) % human_readable(MAX_SIZE)

    def __init__(self, name):
        BaseError.__init__(self, _('File too large'), name)
Exemple #18
0
 def paint(self, painter, option, index):
     top_level = not index.parent().isValid()
     hover = option.state & QStyle.State_MouseOver
     if hover:
         if top_level:
             suffix = '%s(%d)' % (NBSP, index.model().rowCount(index))
         else:
             try:
                 suffix = NBSP + human_readable(current_container().filesize(unicode(index.data(NAME_ROLE) or '')))
             except EnvironmentError:
                 suffix = NBSP + human_readable(0)
         br = painter.boundingRect(option.rect, Qt.AlignRight|Qt.AlignVCenter, suffix)
     if top_level and index.row() > 0:
         option.rect.adjust(0, 5, 0, 0)
         painter.drawLine(option.rect.topLeft(), option.rect.topRight())
         option.rect.adjust(0, 1, 0, 0)
     if hover:
         option.rect.adjust(0, 0, -br.width(), 0)
     QStyledItemDelegate.paint(self, painter, option, index)
     if hover:
         option.rect.adjust(0, 0, br.width(), 0)
         painter.drawText(option.rect, Qt.AlignRight|Qt.AlignVCenter, suffix)
Exemple #19
0
 def render_field(self, db, book_id):
     try:
         field = db.pref('field_under_covers_in_grid', 'title')
         if field == 'size':
             ans = human_readable(db.field_for(field, book_id, default_value=0))
         else:
             mi = db.get_proxy_metadata(book_id)
             display_name, ans, val, fm = mi.format_field_extended(field)
             if fm and fm['datatype'] == 'rating':
                 ans = u'\u2605' * int(val/2.0) if val is not None else ''
         return '' if ans is None else unicode(ans)
     except Exception:
         if DEBUG:
             import traceback
             traceback.print_exc()
     return ''
Exemple #20
0
 def render_field(self, db, book_id):
     try:
         field = db.pref('field_under_covers_in_grid', 'title')
         if field == 'size':
             ans = human_readable(db.field_for(field, book_id, default_value=0))
         else:
             mi = db.get_proxy_metadata(book_id)
             display_name, ans, val, fm = mi.format_field_extended(field)
             if fm and fm['datatype'] == 'rating':
                 ans = u'\u2605' * int(val/2.0) if val is not None else ''
         return '' if ans is None else unicode(ans)
     except Exception:
         if DEBUG:
             import traceback
             traceback.print_exc()
     return ''
    def render_field(self, db, book_id):
        try:
            field = db.pref("field_under_covers_in_grid", "title")
            if field == "size":
                ans = human_readable(db.field_for(field, book_id, default_value=0))
            else:
                mi = db.get_proxy_metadata(book_id)
                display_name, ans, val, fm = mi.format_field_extended(field)
                if fm and fm["datatype"] == "rating":
                    ans = "\u2605" * int(val / 2.0) if val is not None else ""
            return "" if ans is None else unicode(ans)
        except Exception:
            if DEBUG:
                import traceback

                traceback.print_exc()
        return ""
Exemple #22
0
    def add_image_diff(self, left_data, right_data):
        def load(data):
            p = QPixmap()
            p.loadFromData(as_bytes(data))
            try:
                dpr = self.devicePixelRatioF()
            except AttributeError:
                dpr = self.devicePixelRatio()
            p.setDevicePixelRatio(dpr)
            if data and p.isNull():
                p = self.failed_img
            return p

        left_img, right_img = load(left_data), load(right_data)
        change = []
        # Let any initial resizing of the window finish in case this is the
        # first diff, to avoid the expensive resize calculation later
        QApplication.processEvents(
            QEventLoop.ProcessEventsFlag.ExcludeUserInputEvents
            | QEventLoop.ProcessEventsFlag.ExcludeSocketNotifiers)
        for v, img, size in ((self.left, left_img, len(left_data)),
                             (self.right, right_img, len(right_data))):
            c = v.textCursor()
            c.movePosition(c.End)
            start = c.block().blockNumber()
            lines, w = self.get_lines_for_image(img, v)
            c.movePosition(c.StartOfBlock)
            if size > 0:
                c.beginEditBlock()
                c.insertText(
                    _('Size: {0} Resolution: {1}x{2}').format(
                        human_readable(size), img.width(), img.height()))
                for i in range(lines + 1):
                    c.insertBlock()
            change.extend((start, c.block().blockNumber()))
            c.insertBlock()
            c.endEditBlock()
            v.images[start] = (img, w, lines)
        change.append('replace' if left_data and right_data else
                      'delete' if left_data else 'insert')
        self.left.changes.append((change[0], change[1], change[-1]))
        self.right.changes.append((change[2], change[3], change[-1]))
        QApplication.processEvents(
            QEventLoop.ProcessEventsFlag.ExcludeUserInputEvents
            | QEventLoop.ProcessEventsFlag.ExcludeSocketNotifiers)
Exemple #23
0
 def render_field(self, db, book_id):
     is_stars = False
     try:
         field = db.pref('field_under_covers_in_grid', 'title')
         if field == 'size':
             ans = human_readable(db.field_for(field, book_id, default_value=0))
         else:
             mi = db.get_proxy_metadata(book_id)
             display_name, ans, val, fm = mi.format_field_extended(field)
             if fm and fm['datatype'] == 'rating':
                 ans = rating_to_stars(val, fm['display'].get('allow_half_stars', False))
                 is_stars = True
         return ('' if ans is None else unicode_type(ans)), is_stars
     except Exception:
         if DEBUG:
             import traceback
             traceback.print_exc()
     return '', is_stars
Exemple #24
0
 def render_field(self, db, book_id):
     is_stars = False
     try:
         field = db.pref('field_under_covers_in_grid', 'title')
         if field == 'size':
             ans = human_readable(db.field_for(field, book_id, default_value=0))
         else:
             mi = db.get_proxy_metadata(book_id)
             display_name, ans, val, fm = mi.format_field_extended(field)
             if fm and fm['datatype'] == 'rating':
                 ans = rating_to_stars(val, fm['display'].get('allow_half_stars', False))
                 is_stars = True
         return ('' if ans is None else unicode_type(ans)), is_stars
     except Exception:
         if DEBUG:
             import traceback
             traceback.print_exc()
     return '', is_stars
Exemple #25
0
 def paint(self, painter, option, index):
     name = index.data(Qt.DisplayRole)
     sz = human_readable(index.data(Qt.UserRole))
     pmap = index.data(Qt.UserRole+1)
     irect = option.rect.adjusted(0, 5, 0, -5)
     irect.setRight(irect.left() + 70)
     if pmap is None:
         pmap = QPixmap(current_container().get_file_path_for_processing(name))
         scaled, nwidth, nheight = fit_image(pmap.width(), pmap.height(), irect.width(), irect.height())
         if scaled:
             pmap = pmap.scaled(nwidth, nheight, transformMode=Qt.SmoothTransformation)
         index.model().setData(index, pmap, Qt.UserRole+1)
     x, y = (irect.width() - pmap.width())//2, (irect.height() - pmap.height())//2
     r = irect.adjusted(x, y, -x, -y)
     QStyledItemDelegate.paint(self, painter, option, QModelIndex())
     painter.drawPixmap(r, pmap)
     trect = irect.adjusted(irect.width() + 10, 0, 0, 0)
     trect.setRight(option.rect.right())
     painter.save()
     if option.state & QStyle.State_Selected:
         painter.setPen(QPen(option.palette.color(option.palette.HighlightedText)))
     painter.drawText(trect, Qt.AlignVCenter | Qt.AlignLeft, name + '\n' + sz)
     painter.restore()
Exemple #26
0
 def human_readable_size(self):
     """ File size in human readable form """
     return human_readable(self.size)
Exemple #27
0
 def export_lib_text(self, lpath, size=None):
     return _('{0} [Size: {1}]\nin {2}').format(
         os.path.basename(lpath), ('' if size < 0 else human_readable(size))
         if size is not None else _('Calculating...'),
         os.path.dirname(lpath))
Exemple #28
0
    def mobile(self, start='1', num='25', sort='date', search='',
                _=None, order='descending'):
        '''
        Serves metadata from the calibre database as XML.

        :param sort: Sort results by ``sort``. Can be one of `title,author,rating`.
        :param search: Filter results by ``search`` query. See :class:`SearchQueryParser` for query syntax
        :param start,num: Return the slice `[start:start+num]` of the sorted and filtered results
        :param _: Firefox seems to sometimes send this when using XMLHttpRequest with no caching
        '''
        try:
            start = int(start)
        except ValueError:
            raise cherrypy.HTTPError(400, 'start: %s is not an integer'%start)
        try:
            num = int(num)
        except ValueError:
            raise cherrypy.HTTPError(400, 'num: %s is not an integer'%num)
        if not search:
            search = ''
        if isbytestring(search):
            search = search.decode('UTF-8')
        ids = self.db.search_getting_ids(search.strip(), self.search_restriction)
        FM = self.db.FIELD_MAP
        items = [r for r in iter(self.db) if r[FM['id']] in ids]
        if sort is not None:
            self.sort(items, sort, (order.lower().strip() == 'ascending'))

        CFM = self.db.field_metadata
        CKEYS = [key for key in sorted(custom_fields_to_display(self.db),
                                       key=lambda x:sort_key(CFM[x]['name']))]
        # This method uses its own book dict, not the Metadata dict. The loop
        # below could be changed to use db.get_metadata instead of reading
        # info directly from the record made by the view, but it doesn't seem
        # worth it at the moment.
        books = []
        for record in items[(start-1):(start-1)+num]:
            book = {'formats':record[FM['formats']], 'size':record[FM['size']]}
            if not book['formats']:
                book['formats'] = ''
            if not book['size']:
                book['size'] = 0
            book['size'] = human_readable(book['size'])

            aus = record[FM['authors']] if record[FM['authors']] else __builtin__._('Unknown')
            aut_is = CFM['authors']['is_multiple']
            authors = aut_is['list_to_ui'].join([i.replace('|', ',') for i in aus.split(',')])
            book['authors'] = authors
            book['series_index'] = fmt_sidx(float(record[FM['series_index']]))
            book['series'] = record[FM['series']]
            book['tags'] = format_tag_string(record[FM['tags']], ',',
                                             no_tag_count=True)
            book['title'] = record[FM['title']]
            for x in ('timestamp', 'pubdate'):
                book[x] = strftime('%d %b, %Y', record[FM[x]])
            book['id'] = record[FM['id']]
            books.append(book)
            for key in CKEYS:
                def concat(name, val):
                    return '%s:#:%s'%(name, unicode(val))
                mi = self.db.get_metadata(record[CFM['id']['rec_index']], index_is_id=True)
                name, val = mi.format_field(key)
                if not val:
                    continue
                datatype = CFM[key]['datatype']
                if datatype in ['comments']:
                    continue
                if datatype == 'text' and CFM[key]['is_multiple']:
                    book[key] = concat(name,
                                       format_tag_string(val,
                                           CFM[key]['is_multiple']['ui_to_list'],
                                           no_tag_count=True,
                                           joinval=CFM[key]['is_multiple']['list_to_ui']))
                else:
                    book[key] = concat(name, val)

        updated = self.db.last_modified()

        cherrypy.response.headers['Content-Type'] = 'text/html; charset=utf-8'
        cherrypy.response.headers['Last-Modified'] = self.last_modified(updated)

        url_base = "/mobile?search=" + search+";order="+order+";sort="+sort+";num="+str(num)

        raw = html.tostring(build_index(books, num, search, sort, order,
                             start, len(ids), url_base, CKEYS,
                             self.opts.url_prefix),
                             encoding='utf-8',
                             pretty_print=True)
        # tostring's include_meta_content_type is broken
        raw = raw.replace('<head>', '<head>\n'
                '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">')
        return raw
Exemple #29
0
 def evaluate(self, formatter, kwargs, mi, locals, val):
     try:
         return human_readable(round(float(val)))
     except:
         return ""
Exemple #30
0
 def update_cg_cache_size(self, size):
     self.cover_grid_current_disk_cache.setText(
         _('Current space used: %s') % human_readable(size))
Exemple #31
0
 def update_cg_cache_size(self, size):
     self.cover_grid_current_disk_cache.setText(
         _('Current space used: %s') % human_readable(size))
Exemple #32
0
 def human_readable_size(self):
     """ File size in human readable form """
     return human_readable(self.size)
Exemple #33
0
    def mobile(self, start="1", num="25", sort="date", search="", _=None, order="descending"):
        """
        Serves metadata from the calibre database as XML.

        :param sort: Sort results by ``sort``. Can be one of `title,author,rating`.
        :param search: Filter results by ``search`` query. See :class:`SearchQueryParser` for query syntax
        :param start,num: Return the slice `[start:start+num]` of the sorted and filtered results
        :param _: Firefox seems to sometimes send this when using XMLHttpRequest with no caching
        """
        try:
            start = int(start)
        except ValueError:
            raise cherrypy.HTTPError(400, "start: %s is not an integer" % start)
        try:
            num = int(num)
        except ValueError:
            raise cherrypy.HTTPError(400, "num: %s is not an integer" % num)
        if not search:
            search = ""
        if isbytestring(search):
            search = search.decode("UTF-8")
        ids = self.search_for_books(search)
        FM = self.db.FIELD_MAP
        items = [r for r in iter(self.db) if r[FM["id"]] in ids]
        if sort is not None:
            self.sort(items, sort, (order.lower().strip() == "ascending"))

        CFM = self.db.field_metadata
        CKEYS = [key for key in sorted(custom_fields_to_display(self.db), key=lambda x: sort_key(CFM[x]["name"]))]
        # This method uses its own book dict, not the Metadata dict. The loop
        # below could be changed to use db.get_metadata instead of reading
        # info directly from the record made by the view, but it doesn't seem
        # worth it at the moment.
        books = []
        for record in items[(start - 1) : (start - 1) + num]:
            book = {"formats": record[FM["formats"]], "size": record[FM["size"]]}
            if not book["formats"]:
                book["formats"] = ""
            if not book["size"]:
                book["size"] = 0
            book["size"] = human_readable(book["size"])

            aus = record[FM["authors"]] if record[FM["authors"]] else __builtin__._("Unknown")
            aut_is = CFM["authors"]["is_multiple"]
            authors = aut_is["list_to_ui"].join([i.replace("|", ",") for i in aus.split(",")])
            book["authors"] = authors
            book["series_index"] = fmt_sidx(float(record[FM["series_index"]]))
            book["series"] = record[FM["series"]]
            book["tags"] = format_tag_string(record[FM["tags"]], ",", no_tag_count=True)
            book["title"] = record[FM["title"]]
            for x in ("timestamp", "pubdate"):
                book[x] = strftime("%d %b, %Y", as_local_time(record[FM[x]]))
            book["id"] = record[FM["id"]]
            books.append(book)
            for key in CKEYS:

                def concat(name, val):
                    return "%s:#:%s" % (name, unicode(val))

                mi = self.db.get_metadata(record[CFM["id"]["rec_index"]], index_is_id=True)
                name, val = mi.format_field(key)
                if not val:
                    continue
                datatype = CFM[key]["datatype"]
                if datatype in ["comments"]:
                    continue
                if datatype == "text" and CFM[key]["is_multiple"]:
                    book[key] = concat(
                        name,
                        format_tag_string(
                            val,
                            CFM[key]["is_multiple"]["ui_to_list"],
                            no_tag_count=True,
                            joinval=CFM[key]["is_multiple"]["list_to_ui"],
                        ),
                    )
                else:
                    book[key] = concat(name, val)

        updated = self.db.last_modified()

        cherrypy.response.headers["Content-Type"] = "text/html; charset=utf-8"
        cherrypy.response.headers["Last-Modified"] = self.last_modified(updated)

        q = {
            b"search": search.encode("utf-8"),
            b"order": order.encode("utf-8"),
            b"sort": sort.encode("utf-8"),
            b"num": str(num).encode("utf-8"),
        }
        url_base = "/mobile?" + urlencode(q)
        ua = cherrypy.request.headers.get("User-Agent", "").strip()
        have_kobo_browser = self.is_kobo_browser(ua)

        raw = html.tostring(
            build_index(
                books,
                num,
                search,
                sort,
                order,
                start,
                len(ids),
                url_base,
                CKEYS,
                self.opts.url_prefix,
                have_kobo_browser=have_kobo_browser,
            ),
            encoding="utf-8",
            pretty_print=True,
        )
        # tostring's include_meta_content_type is broken
        raw = raw.replace("<head>", "<head>\n" '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">')
        return raw
Exemple #34
0
    def mobile(self,
               start='1',
               num='25',
               sort='date',
               search='',
               _=None,
               order='descending'):
        '''
        Serves metadata from the calibre database as XML.

        :param sort: Sort results by ``sort``. Can be one of `title,author,rating`.
        :param search: Filter results by ``search`` query. See :class:`SearchQueryParser` for query syntax
        :param start,num: Return the slice `[start:start+num]` of the sorted and filtered results
        :param _: Firefox seems to sometimes send this when using XMLHttpRequest with no caching
        '''
        try:
            start = int(start)
        except ValueError:
            raise cherrypy.HTTPError(400,
                                     'start: %s is not an integer' % start)
        try:
            num = int(num)
        except ValueError:
            raise cherrypy.HTTPError(400, 'num: %s is not an integer' % num)
        if not search:
            search = ''
        if isbytestring(search):
            search = search.decode('UTF-8')
        ids = self.db.search_getting_ids(search.strip(),
                                         self.search_restriction)
        FM = self.db.FIELD_MAP
        items = [r for r in iter(self.db) if r[FM['id']] in ids]
        if sort is not None:
            self.sort(items, sort, (order.lower().strip() == 'ascending'))

        CFM = self.db.field_metadata
        CKEYS = [
            key for key in sorted(custom_fields_to_display(self.db),
                                  key=lambda x: sort_key(CFM[x]['name']))
        ]
        # This method uses its own book dict, not the Metadata dict. The loop
        # below could be changed to use db.get_metadata instead of reading
        # info directly from the record made by the view, but it doesn't seem
        # worth it at the moment.
        books = []
        for record in items[(start - 1):(start - 1) + num]:
            book = {
                'formats': record[FM['formats']],
                'size': record[FM['size']]
            }
            if not book['formats']:
                book['formats'] = ''
            if not book['size']:
                book['size'] = 0
            book['size'] = human_readable(book['size'])

            aus = record[FM['authors']] if record[
                FM['authors']] else __builtin__._('Unknown')
            aut_is = CFM['authors']['is_multiple']
            authors = aut_is['list_to_ui'].join(
                [i.replace('|', ',') for i in aus.split(',')])
            book['authors'] = authors
            book['series_index'] = fmt_sidx(float(record[FM['series_index']]))
            book['series'] = record[FM['series']]
            book['tags'] = format_tag_string(record[FM['tags']],
                                             ',',
                                             no_tag_count=True)
            book['title'] = record[FM['title']]
            for x in ('timestamp', 'pubdate'):
                book[x] = strftime('%d %b, %Y', record[FM[x]])
            book['id'] = record[FM['id']]
            books.append(book)
            for key in CKEYS:

                def concat(name, val):
                    return '%s:#:%s' % (name, unicode(val))

                mi = self.db.get_metadata(record[CFM['id']['rec_index']],
                                          index_is_id=True)
                name, val = mi.format_field(key)
                if not val:
                    continue
                datatype = CFM[key]['datatype']
                if datatype in ['comments']:
                    continue
                if datatype == 'text' and CFM[key]['is_multiple']:
                    book[key] = concat(
                        name,
                        format_tag_string(
                            val,
                            CFM[key]['is_multiple']['ui_to_list'],
                            no_tag_count=True,
                            joinval=CFM[key]['is_multiple']['list_to_ui']))
                else:
                    book[key] = concat(name, val)

        updated = self.db.last_modified()

        cherrypy.response.headers['Content-Type'] = 'text/html; charset=utf-8'
        cherrypy.response.headers['Last-Modified'] = self.last_modified(
            updated)

        url_base = "/mobile?search=" + search + ";order=" + order + ";sort=" + sort + ";num=" + str(
            num)

        raw = html.tostring(build_index(books, num, search, sort, order, start,
                                        len(ids), url_base, CKEYS,
                                        self.opts.url_prefix),
                            encoding='utf-8',
                            pretty_print=True)
        # tostring's include_meta_content_type is broken
        raw = raw.replace(
            '<head>', '<head>\n'
            '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">'
        )
        return raw
Exemple #35
0
def main():
    from calibre.utils.terminal import geometry
    cols = geometry()[0]

    parser = OptionParser(
        usage="usage: %prog [options] command args\n\ncommand " +
        "is one of: info, books, df, ls, cp, mkdir, touch, cat, rm, eject, test_file\n\n"
        + "For help on a particular command: %prog command",
        version=__appname__ + " version: " + __version__)
    parser.add_option(
        "--log-packets",
        help="print out packet stream to stdout. " +
        "The numbers in the left column are byte offsets that allow the packet size to be read off easily.",
        dest="log_packets",
        action="store_true",
        default=False)
    parser.remove_option("-h")
    parser.disable_interspersed_args()  # Allow unrecognized options
    options, args = parser.parse_args()

    if len(args) < 1:
        parser.print_help()
        return 1

    command = args[0]
    args = args[1:]
    dev = None
    scanner = DeviceScanner()
    scanner.scan()
    connected_devices = []

    for d in device_plugins():
        try:
            d.startup()
        except:
            print('Startup failed for device plugin: %s' % d)
        if d.MANAGES_DEVICE_PRESENCE:
            cd = d.detect_managed_devices(scanner.devices)
            if cd is not None:
                connected_devices.append((cd, d))
                dev = d
                break
            continue
        ok, det = scanner.is_device_connected(d)
        if ok:
            dev = d
            dev.reset(log_packets=options.log_packets, detected_device=det)
            connected_devices.append((det, dev))

    if dev is None:
        print('Unable to find a connected ebook reader.', file=sys.stderr)
        shutdown_plugins()
        return 1

    for det, d in connected_devices:
        try:
            d.open(det, None)
        except:
            continue
        else:
            dev = d
            d.specialize_global_preferences(device_prefs)
            break

    try:
        if command == "df":
            total = dev.total_space(end_session=False)
            free = dev.free_space()
            where = ("Memory", "Card A", "Card B")
            print("Filesystem\tSize \tUsed \tAvail \tUse%")
            for i in range(3):
                print("%-10s\t%s\t%s\t%s\t%s" %
                      (where[i], human_readable(
                          total[i]), human_readable(total[i] - free[i]),
                       human_readable(free[i]),
                       unicode_type(0 if total[i] ==
                                    0 else int(100 * (total[i] - free[i]) /
                                               (total[i] * 1.))) + "%"))
        elif command == 'eject':
            dev.eject()
        elif command == "books":
            print("Books in main memory:")
            for book in dev.books():
                print(book)
            print("\nBooks on storage carda:")
            for book in dev.books(oncard='carda'):
                print(book)
            print("\nBooks on storage cardb:")
            for book in dev.books(oncard='cardb'):
                print(book)
        elif command == "mkdir":
            parser = OptionParser(
                usage=
                "usage: %prog mkdir [options] path\nCreate a folder on the device\n\npath must begin with / or card:/"
            )
            if len(args) != 1:
                parser.print_help()
                sys.exit(1)
            dev.mkdir(args[0])
        elif command == "ls":
            parser = OptionParser(
                usage=
                "usage: %prog ls [options] path\nList files on the device\n\npath must begin with / or card:/"
            )
            parser.add_option(
                "-l",
                help=
                "In addition to the name of each file, print the file type, permissions, and  timestamp  (the  modification time, in the local timezone). Times are local.",  # noqa
                dest="ll",
                action="store_true",
                default=False)
            parser.add_option(
                "-R",
                help=
                "Recursively list subfolders encountered. /dev and /proc are omitted",
                dest="recurse",
                action="store_true",
                default=False)
            parser.remove_option("-h")
            parser.add_option("-h",
                              "--human-readable",
                              help="show sizes in human readable format",
                              dest="hrs",
                              action="store_true",
                              default=False)
            options, args = parser.parse_args(args)
            if len(args) != 1:
                parser.print_help()
                return 1
            print(ls(dev,
                     args[0],
                     recurse=options.recurse,
                     ll=options.ll,
                     human_readable_size=options.hrs,
                     cols=cols),
                  end=' ')
        elif command == "info":
            info(dev)
        elif command == "cp":
            usage="usage: %prog cp [options] source destination\nCopy files to/from the device\n\n"+\
            "One of source or destination must be a path on the device. \n\nDevice paths have the form\n"+\
            "dev:mountpoint/my/path\n"+\
            "where mountpoint is one of / or carda: or cardb:/\n\n"+\
            "source must point to a file for which you have read permissions\n"+\
            "destination must point to a file or folder for which you have write permissions"
            parser = OptionParser(usage=usage)
            parser.add_option(
                '-f',
                '--force',
                dest='force',
                action='store_true',
                default=False,
                help='Overwrite the destination file if it exists already.')
            options, args = parser.parse_args(args)
            if len(args) != 2:
                parser.print_help()
                return 1
            if args[0].startswith("dev:"):
                outfile = args[1]
                path = args[0][4:]
                if path.endswith("/"):
                    path = path[:-1]
                if os.path.isdir(outfile):
                    outfile = os.path.join(outfile, path[path.rfind("/") + 1:])
                try:
                    outfile = lopen(outfile, "wb")
                except IOError as e:
                    print(e, file=sys.stderr)
                    parser.print_help()
                    return 1
                dev.get_file(path, outfile)
                fsync(outfile)
                outfile.close()
            elif args[1].startswith("dev:"):
                try:
                    infile = lopen(args[0], "rb")
                except IOError as e:
                    print(e, file=sys.stderr)
                    parser.print_help()
                    return 1
                dev.put_file(infile, args[1][4:], replace_file=options.force)
                infile.close()
            else:
                parser.print_help()
                return 1
        elif command == "cat":
            outfile = sys.stdout
            parser = OptionParser(
                usage=
                "usage: %prog cat path\nShow file on the device\n\npath should point to a file on the device and must begin with /,a:/ or b:/"
            )
            options, args = parser.parse_args(args)
            if len(args) != 1:
                parser.print_help()
                return 1
            if args[0].endswith("/"):
                path = args[0][:-1]
            else:
                path = args[0]
            outfile = sys.stdout
            dev.get_file(path, outfile)
        elif command == "rm":
            parser = OptionParser(
                usage=
                "usage: %prog rm path\nDelete files from the device\n\npath should point to a file or empty folder on the device "
                + "and must begin with / or card:/\n\n" +
                "rm will DELETE the file. Be very CAREFUL")
            options, args = parser.parse_args(args)
            if len(args) != 1:
                parser.print_help()
                return 1
            dev.rm(args[0])
        elif command == "touch":
            parser = OptionParser(
                usage=
                "usage: %prog touch path\nCreate an empty file on the device\n\npath should point to a file on the device and must begin with /,a:/ or b:/\n\n"
                +  # noqa
                "Unfortunately, I cant figure out how to update file times on the device, so if path already exists, touch does nothing"
            )
            options, args = parser.parse_args(args)
            if len(args) != 1:
                parser.print_help()
                return 1
            dev.touch(args[0])
        elif command == 'test_file':
            parser = OptionParser(usage=(
                "usage: %prog test_file path\n"
                'Open device, copy file specified by path to device and '
                'then eject device.'))
            options, args = parser.parse_args(args)
            if len(args) != 1:
                parser.print_help()
                return 1
            path = args[0]
            from calibre.ebooks.metadata.meta import get_metadata
            mi = get_metadata(lopen(path, 'rb'),
                              path.rpartition('.')[-1].lower())
            print(
                dev.upload_books([args[0]], [os.path.basename(args[0])],
                                 end_session=False,
                                 metadata=[mi]))
            dev.eject()
        else:
            parser.print_help()
            if getattr(dev, 'handle', False):
                dev.close()
            return 1
    except DeviceLocked:
        print("The device is locked. Use the --unlock option", file=sys.stderr)
    except (ArgumentError, DeviceError) as e:
        print(e, file=sys.stderr)
        return 1
    finally:
        shutdown_plugins()

    return 0
Exemple #36
0
def main():
    from calibre.utils.terminal import geometry
    cols = geometry()[0]

    parser = OptionParser(usage="usage: %prog [options] command args\n\ncommand "+
            "is one of: info, books, df, ls, cp, mkdir, touch, cat, rm, eject, test_file\n\n"+
    "For help on a particular command: %prog command", version=__appname__+" version: " + __version__)
    parser.add_option("--log-packets", help="print out packet stream to stdout. "+\
                    "The numbers in the left column are byte offsets that allow the packet size to be read off easily.",
    dest="log_packets", action="store_true", default=False)
    parser.remove_option("-h")
    parser.disable_interspersed_args() # Allow unrecognized options
    options, args = parser.parse_args()

    if len(args) < 1:
        parser.print_help()
        return 1

    command = args[0]
    args = args[1:]
    dev = None
    scanner = DeviceScanner()
    scanner.scan()
    connected_devices = []

    for d in device_plugins():
        try:
            d.startup()
        except:
            print ('Startup failed for device plugin: %s'%d)
        if d.MANAGES_DEVICE_PRESENCE:
            cd = d.detect_managed_devices(scanner.devices)
            if cd is not None:
                connected_devices.append((cd, d))
                dev = d
                break
            continue
        ok, det = scanner.is_device_connected(d)
        if ok:
            dev = d
            dev.reset(log_packets=options.log_packets, detected_device=det)
            connected_devices.append((det, dev))

    if dev is None:
        print >>sys.stderr, 'Unable to find a connected ebook reader.'
        shutdown_plugins()
        return 1

    for det, d in connected_devices:
        try:
            d.open(det, None)
        except:
            continue
        else:
            dev = d
            d.specialize_global_preferences(device_prefs)
            break


    try:
        if command == "df":
            total = dev.total_space(end_session=False)
            free = dev.free_space()
            where = ("Memory", "Card A", "Card B")
            print "Filesystem\tSize \tUsed \tAvail \tUse%"
            for i in range(3):
                print "%-10s\t%s\t%s\t%s\t%s"%(where[i], human_readable(total[i]), human_readable(total[i]-free[i]), human_readable(free[i]),\
                                                                            str(0 if total[i]==0 else int(100*(total[i]-free[i])/(total[i]*1.)))+"%")
        elif command == 'eject':
            dev.eject()
        elif command == "books":
            print "Books in main memory:"
            for book in dev.books():
                print book
            print "\nBooks on storage carda:"
            for book in dev.books(oncard='carda'): print book
            print "\nBooks on storage cardb:"
            for book in dev.books(oncard='cardb'): print book
        elif command == "mkdir":
            parser = OptionParser(usage="usage: %prog mkdir [options] path\nCreate a directory on the device\n\npath must begin with / or card:/")
            if len(args) != 1:
                parser.print_help()
                sys.exit(1)
            dev.mkdir(args[0])
        elif command == "ls":
            parser = OptionParser(usage="usage: %prog ls [options] path\nList files on the device\n\npath must begin with / or card:/")
            parser.add_option("-l", help="In addition to the name of each file, print the file type, permissions, and  timestamp  (the  modification time, in the local timezone). Times are local.", dest="ll", action="store_true", default=False)
            parser.add_option("-R", help="Recursively list subdirectories encountered. /dev and /proc are omitted", dest="recurse", action="store_true", default=False)
            parser.remove_option("-h")
            parser.add_option("-h", "--human-readable", help="show sizes in human readable format", dest="hrs", action="store_true", default=False)
            options, args = parser.parse_args(args)
            if len(args) != 1:
                parser.print_help()
                return 1
            print ls(dev, args[0], recurse=options.recurse, ll=options.ll, human_readable_size=options.hrs, cols=cols),
        elif command == "info":
            info(dev)
        elif command == "cp":
            usage="usage: %prog cp [options] source destination\nCopy files to/from the device\n\n"+\
            "One of source or destination must be a path on the device. \n\nDevice paths have the form\n"+\
            "dev:mountpoint/my/path\n"+\
            "where mountpoint is one of / or card:/\n\n"+\
            "source must point to a file for which you have read permissions\n"+\
            "destination must point to a file or directory for which you have write permissions"
            parser = OptionParser(usage=usage)
            parser.add_option('-f', '--force', dest='force', action='store_true', default=False,
                              help='Overwrite the destination file if it exists already.')
            options, args = parser.parse_args(args)
            if len(args) != 2:
                parser.print_help()
                return 1
            if args[0].startswith("dev:"):
                outfile = args[1]
                path = args[0][7:]
                if path.endswith("/"): path = path[:-1]
                if os.path.isdir(outfile):
                    outfile = os.path.join(outfile, path[path.rfind("/")+1:])
                try:
                    outfile = open(outfile, "wb")
                except IOError as e:
                    print >> sys.stderr, e
                    parser.print_help()
                    return 1
                dev.get_file(path, outfile)
                outfile.close()
            elif args[1].startswith("dev:"):
                try:
                    infile = open(args[0], "rb")
                except IOError as e:
                    print >> sys.stderr, e
                    parser.print_help()
                    return 1
                try:
                    dev.put_file(infile, args[1][7:])
                except PathError as err:
                    if options.force and 'exists' in str(err):
                        dev.del_file(err.path, False)
                        dev.put_file(infile, args[1][7:])
                    else:
                        raise
                infile.close()
            else:
                parser.print_help()
                return 1
        elif command == "cat":
            outfile = sys.stdout
            parser = OptionParser(usage="usage: %prog cat path\nShow file on the device\n\npath should point to a file on the device and must begin with /,a:/ or b:/")
            options, args = parser.parse_args(args)
            if len(args) != 1:
                parser.print_help()
                return 1
            if args[0].endswith("/"): path = args[0][:-1]
            else: path = args[0]
            outfile = sys.stdout
            dev.get_file(path, outfile)
        elif command == "rm":
            parser = OptionParser(usage="usage: %prog rm path\nDelete files from the device\n\npath should point to a file or empty directory on the device "+\
                                  "and must begin with / or card:/\n\n"+\
                                  "rm will DELETE the file. Be very CAREFUL")
            options, args = parser.parse_args(args)
            if len(args) != 1:
                parser.print_help()
                return 1
            dev.rm(args[0])
        elif command == "touch":
            parser = OptionParser(usage="usage: %prog touch path\nCreate an empty file on the device\n\npath should point to a file on the device and must begin with /,a:/ or b:/\n\n"+
            "Unfortunately, I cant figure out how to update file times on the device, so if path already exists, touch does nothing" )
            options, args = parser.parse_args(args)
            if len(args) != 1:
                parser.print_help()
                return 1
            dev.touch(args[0])
        elif command == 'test_file':
            parser = OptionParser(usage=("usage: %prog test_file path\n"
                'Open device, copy file specified by path to device and '
                'then eject device.'))
            options, args = parser.parse_args(args)
            if len(args) != 1:
                parser.print_help()
                return 1
            path = args[0]
            from calibre.ebooks.metadata.meta import get_metadata
            mi = get_metadata(open(path, 'rb'), path.rpartition('.')[-1].lower())
            print dev.upload_books([args[0]], [os.path.basename(args[0])],
                    end_session=False, metadata=[mi])
            dev.eject()
        else:
            parser.print_help()
            if getattr(dev, 'handle', False): dev.close()
            return 1
    except DeviceLocked:
        print >> sys.stderr, "The device is locked. Use the --unlock option"
    except (ArgumentError, DeviceError) as e:
        print >>sys.stderr, e
        return 1
    finally:
        shutdown_plugins()

    return 0
Exemple #37
0
 def fget(self):
     return human_readable(self.size)
Exemple #38
0
 def fget(self):
     return human_readable(self.size)
Exemple #39
0
 def evaluate(self, formatter, kwargs, mi, locals, val):
     try:
         return human_readable(round(float(val)))
     except:
         return ''
Exemple #40
0
 def export_lib_text(self, lpath, size=None):
     return _('{0} [Size: {1}]\nin {2}').format(
         os.path.basename(lpath), ('' if size < 0 else human_readable(size))
         if size is not None else _('Calculating...'), os.path.dirname(lpath))