示例#1
0
文件: commands.py 项目: silky/beets
def remove_items(lib, query, album, delete):
    """Remove items matching query from lib. If album, then match and
    remove whole albums. If delete, also remove files from disk.
    """
    # Get the matching items.
    items, albums = _do_query(lib, query, album)

    # Show all the items.
    for item in items:
        ui.print_obj(item, lib)

    # Confirm with user.
    print_()
    if delete:
        prompt = 'Really DELETE %i files (y/n)?' % len(items)
    else:
        prompt = 'Really remove %i items from the library (y/n)?' % \
                 len(items)
    if not ui.input_yn(prompt, True):
        return

    # Remove (and possibly delete) items.
    with lib.transaction():
        for obj in (albums if album else items):
            obj.remove(delete)
示例#2
0
文件: commands.py 项目: encukou/beets
def remove_items(lib, query, album, delete=False):
    """Remove items matching query from lib. If album, then match and
    remove whole albums. If delete, also remove files from disk.
    """
    # Get the matching items.
    items, albums = _do_query(lib, query, album)

    # Show all the items.
    for item in items:
        print_(item.artist + ' - ' + item.album + ' - ' + item.title)

    # Confirm with user.
    print_()
    if delete:
        prompt = 'Really DELETE %i files (y/n)?' % len(items)
    else:
        prompt = 'Really remove %i items from the library (y/n)?' % \
                 len(items)
    if not ui.input_yn(prompt, True):
        return

    # Remove (and possibly delete) items.
    with lib.transaction():
        if album:
            for al in albums:
                al.remove(delete)
        else:
            for item in items:
                lib.remove(item, delete)
示例#3
0
文件: commands.py 项目: jlefley/beets
def remove_items(lib, query, album, delete):
    """Remove items matching query from lib. If album, then match and
    remove whole albums. If delete, also remove files from disk.
    """
    # Get the matching items.
    items, albums = _do_query(lib, query, album)

    # Show all the items.
    for item in items:
        ui.print_obj(item, lib)

    # Confirm with user.
    print_()
    if delete:
        prompt = 'Really DELETE %i files (y/n)?' % len(items)
    else:
        prompt = 'Really remove %i items from the library (y/n)?' % \
                 len(items)
    if not ui.input_yn(prompt, True):
        return

    # Remove (and possibly delete) items.
    with lib.transaction():
        for obj in (albums if album else items):
            obj.remove(delete)
示例#4
0
def remove_items(lib, query, album, delete=False):
    """Remove items matching query from lib. If album, then match and
    remove whole albums. If delete, also remove files from disk.
    """
    # Get the matching items.
    items, albums = _do_query(lib, query, album)

    # Show all the items.
    for item in items:
        print_(item.artist + ' - ' + item.album + ' - ' + item.title)

    # Confirm with user.
    print_()
    if delete:
        prompt = 'Really DELETE %i files (y/n)?' % len(items)
    else:
        prompt = 'Really remove %i items from the library (y/n)?' % \
                 len(items)
    if not ui.input_yn(prompt, True):
        return

    # Remove (and possibly delete) items.
    if album:
        for al in albums:
            al.remove(delete)
    else:
        for item in items:
            lib.remove(item, delete)

    lib.save()
示例#5
0
    def convert_func(self, lib, opts, args):
        dest = opts.dest or self.config['dest'].get()
        if not dest:
            raise ui.UserError(u'no convert destination set')
        dest = util.bytestring_path(dest)

        threads = opts.threads or self.config['threads'].get(int)

        path_formats = ui.get_path_formats(self.config['paths'] or None)

        fmt = opts.format or self.config['format'].as_str().lower()

        if opts.pretend is not None:
            pretend = opts.pretend
        else:
            pretend = self.config['pretend'].get(bool)

        if opts.hardlink is not None:
            hardlink = opts.hardlink
            link = False
        elif opts.link is not None:
            hardlink = False
            link = opts.link
        else:
            hardlink = self.config['hardlink'].get(bool)
            link = self.config['link'].get(bool)

        if opts.album:
            albums = lib.albums(ui.decargs(args))
            items = [i for a in albums for i in a.items()]
            if not pretend:
                for a in albums:
                    ui.print_(format(a, u''))
        else:
            items = list(lib.items(ui.decargs(args)))
            if not pretend:
                for i in items:
                    ui.print_(format(i, u''))

        if not items:
            self._log.error(u'Empty query result.')
            return
        if not (pretend or opts.yes or ui.input_yn(u"Convert? (Y/n)")):
            return

        if opts.album and self.config['copy_album_art']:
            for album in albums:
                self.copy_album_art(album, dest, path_formats, pretend,
                                    link, hardlink)

        convert = [self.convert_item(dest,
                                     opts.keep_new,
                                     path_formats,
                                     fmt,
                                     pretend,
                                     link,
                                     hardlink)
                   for _ in range(threads)]
        pipe = util.pipeline.Pipeline([iter(items), convert])
        pipe.run_parallel()
示例#6
0
文件: commands.py 项目: encukou/beets
def modify_items(lib, mods, query, write, move, album, color, confirm):
    """Modifies matching items according to key=value assignments."""
    # Parse key=value specifications into a dictionary.
    allowed_keys = library.ALBUM_KEYS if album else library.ITEM_KEYS_WRITABLE
    fsets = {}
    for mod in mods:
        key, value = mod.split('=', 1)
        if key not in allowed_keys:
            raise ui.UserError('"%s" is not a valid field' % key)
        fsets[key] = value

    # Get the items to modify.
    items, albums = _do_query(lib, query, album, False)
    objs = albums if album else items

    # Preview change.
    print_('Modifying %i %ss.' % (len(objs), 'album' if album else 'item'))
    for obj in objs:
        # Identify the changed object.
        if album:
            print_(u'* %s - %s' % (obj.albumartist, obj.album))
        else:
            print_(u'* %s - %s' % (obj.artist, obj.title))

        # Show each change.
        for field, value in fsets.iteritems():
            curval = getattr(obj, field)
            _showdiff(field, curval, value, color)

    # Confirm.
    if confirm:
        extra = ' and write tags' if write else ''
        if not ui.input_yn('Really modify%s (Y/n)?' % extra):
            return

    # Apply changes to database.
    with lib.transaction():
        for obj in objs:
            for field, value in fsets.iteritems():
                setattr(obj, field, value)

            if move:
                cur_path = obj.item_dir() if album else obj.path
                if lib.directory in ancestry(cur_path): # In library?
                    log.debug('moving object %s' % cur_path)
                    if album:
                        obj.move()
                    else:
                        lib.move(obj)

            # When modifying items, we have to store them to the database.
            if not album:
                lib.store(obj)

    # Apply tags if requested.
    if write:
        if album:
            items = itertools.chain(*(a.items() for a in albums))
        for item in items:
            item.write()
示例#7
0
文件: zero.py 项目: JDLH/beets
 def zero_fields(lib, opts, args):
     if not decargs(args) and not input_yn(
             u"Remove fields for all items? (Y/n)",
             True):
         return
     for item in lib.items(decargs(args)):
         self.process_item(item)
示例#8
0
def convert_func(lib, opts, args):
    dest = opts.dest if opts.dest is not None else \
        config['convert']['dest'].get()

    if not dest:
        raise ui.UserError('no convert destination set')

    dest = util.bytestring_path(dest)
    threads = opts.threads if opts.threads is not None else \
        config['convert']['threads'].get(int)
    keep_new = opts.keep_new

    if not config['convert']['paths']:
        path_formats = ui.get_path_formats()
    else:
        path_formats = ui.get_path_formats(config['convert']['paths'])

    ui.commands.list_items(lib, ui.decargs(args), opts.album, None)

    if not ui.input_yn("Convert? (Y/n)"):
        return

    if opts.album:
        items = (i for a in lib.albums(ui.decargs(args)) for i in a.items())
    else:
        items = iter(lib.items(ui.decargs(args)))
    convert = [
        convert_item(dest, keep_new, path_formats) for i in range(threads)
    ]
    pipe = util.pipeline.Pipeline([items, convert])
    pipe.run_parallel()
示例#9
0
文件: convert.py 项目: aereaux/beets
    def convert_func(self, lib, opts, args):
        (dest, threads, path_formats, fmt, pretend, hardlink,
         link) = self._get_opts_and_config(opts)

        if opts.album:
            albums = lib.albums(ui.decargs(args))
            items = [i for a in albums for i in a.items()]
            if not pretend:
                for a in albums:
                    ui.print_(format(a, ''))
        else:
            items = list(lib.items(ui.decargs(args)))
            if not pretend:
                for i in items:
                    ui.print_(format(i, ''))

        if not items:
            self._log.error('Empty query result.')
            return
        if not (pretend or opts.yes or ui.input_yn("Convert? (Y/n)")):
            return

        if opts.album and self.config['copy_album_art']:
            for album in albums:
                self.copy_album_art(album, dest, path_formats, pretend, link,
                                    hardlink)

        self._parallel_convert(dest, opts.keep_new, path_formats, fmt, pretend,
                               link, hardlink, threads, items)
示例#10
0
def convert_func(lib, opts, args):
    dest = opts.dest if opts.dest is not None else \
            config['convert']['dest'].get()

    if not dest:
        raise ui.UserError('no convert destination set')

    dest = util.bytestring_path(dest)
    threads = opts.threads if opts.threads is not None else \
            config['convert']['threads'].get(int)
    keep_new = opts.keep_new

    if not config['convert']['paths']:
        path_formats = ui.get_path_formats()
    else:
        path_formats = ui.get_path_formats(config['convert']['paths'])

    ui.commands.list_items(lib, ui.decargs(args), opts.album, None)

    if not ui.input_yn("Convert? (Y/n)"):
        return

    if opts.album:
        items = (i for a in lib.albums(ui.decargs(args)) for i in a.items())
    else:
        items = iter(lib.items(ui.decargs(args)))
    convert = [convert_item(lib, dest, keep_new, path_formats) for i in range(threads)]
    pipe = util.pipeline.Pipeline([items, convert])
    pipe.run_parallel()
示例#11
0
def modify_items(lib, mods, query, write, move, album, color, confirm):
    """Modifies matching items according to key=value assignments."""
    # Parse key=value specifications into a dictionary.
    allowed_keys = library.ALBUM_KEYS if album else library.ITEM_KEYS_WRITABLE
    fsets = {}
    for mod in mods:
        key, value = mod.split('=', 1)
        if key not in allowed_keys:
            raise ui.UserError('"%s" is not a valid field' % key)
        fsets[key] = value

    # Get the items to modify.
    items, albums = _do_query(lib, query, album, False)
    objs = albums if album else items

    # Preview change.
    print_('Modifying %i %ss.' % (len(objs), 'album' if album else 'item'))
    for obj in objs:
        # Identify the changed object.
        if album:
            print_(u'* %s - %s' % (obj.albumartist, obj.album))
        else:
            print_(u'* %s - %s' % (obj.artist, obj.title))

        # Show each change.
        for field, value in fsets.iteritems():
            curval = getattr(obj, field)
            _showdiff(field, curval, value, color)

    # Confirm.
    if confirm:
        extra = ' and write tags' if write else ''
        if not ui.input_yn('Really modify%s (Y/n)?' % extra):
            return

    # Apply changes to database.
    for obj in objs:
        for field, value in fsets.iteritems():
            setattr(obj, field, value)

        if move:
            cur_path = obj.item_dir() if album else obj.path
            if lib.directory in ancestry(cur_path):  # In library?
                log.debug('moving object %s' % cur_path)
                if album:
                    obj.move()
                else:
                    lib.move(obj)

        # When modifying items, we have to store them to the database.
        if not album:
            lib.store(obj)
    lib.save()

    # Apply tags if requested.
    if write:
        if album:
            items = itertools.chain(*(a.items() for a in albums))
        for item in items:
            item.write()
示例#12
0
文件: commands.py 项目: korozif/beets
def modify_items(lib, mods, query, write, move, album, confirm):
    """Modifies matching items according to key=value assignments."""
    # Parse key=value specifications into a dictionary.
    model_cls = library.Album if album else library.Item
    fsets = {}
    for mod in mods:
        key, value = mod.split('=', 1)
        fsets[key] = model_cls._parse(key, value)

    # Get the items to modify.
    items, albums = _do_query(lib, query, album, False)
    objs = albums if album else items

    # Preview change and collect modified objects.
    print_('Modifying %i %ss.' % (len(objs), 'album' if album else 'item'))
    changed = set()
    for obj in objs:
        # Identify the changed object.
        ui.print_obj(obj, lib)

        # Show each change.
        for field, value in fsets.iteritems():
            if _showdiff(field, obj._get_formatted(field),
                         obj._format(field, value)):
                changed.add(obj)

    # Still something to do?
    if not changed:
        print_('No changes to make.')
        return

    # Confirm action.
    if confirm:
        extra = ' and write tags' if write else ''
        if not ui.input_yn('Really modify%s (Y/n)?' % extra):
            return

    # Apply changes to database.
    with lib.transaction():
        for obj in changed:
            for field, value in fsets.iteritems():
                obj[field] = value

            if move:
                cur_path = obj.path
                if lib.directory in ancestry(cur_path): # In library?
                    log.debug('moving object %s' % cur_path)
                    obj.move()

            obj.store()

    # Apply tags if requested.
    if write:
        if album:
            changed_items = itertools.chain(*(a.items() for a in changed))
        else:
            changed_items = changed
        for item in changed_items:
            item.write()
示例#13
0
def modify_items(lib, mods, dels, query, write, move, album, confirm):
    """Modifies matching items according to key=value assignments."""
    # Parse key=value specifications into a dictionary.
    model_cls = library.Album if album else library.Item
    fsets = {}
    for mod in mods:
        key, value = mod.split('=', 1)
        fsets[key] = model_cls._parse(key, value)

    # Get the items to modify.
    items, albums = _do_query(lib, query, album, False)
    objs = albums if album else items

    # Apply changes *temporarily*, preview them, and collect modified
    # objects.
    print_('Modifying %i %ss.' % (len(objs), 'album' if album else 'item'))
    changed = set()
    for obj in objs:
        for field, value in fsets.iteritems():
            obj[field] = value
        for field in dels:
            del obj[field]
        if ui.show_model_changes(obj):
            changed.add(obj)

    # Still something to do?
    if not changed:
        print_('No changes to make.')
        return

    # Confirm action.
    if confirm:
        extra = ' and write tags' if write else ''
        if not ui.input_yn('Really modify%s (Y/n)?' % extra):
            return

    # Apply changes to database.
    with lib.transaction():
        for obj in changed:
            if move:
                cur_path = obj.path
                if lib.directory in ancestry(cur_path): # In library?
                    log.debug('moving object %s' % cur_path)
                    obj.move()

            obj.store()

    # Apply tags if requested.
    if write:
        if album:
            changed_items = itertools.chain(*(a.items() for a in changed))
        else:
            changed_items = changed
        for item in changed_items:
            try:
                item.write()
            except library.FileOperationError as exc:
                log.error(exc)
示例#14
0
def modify_items(lib, mods, dels, query, write, move, album, confirm):
    """Modifies matching items according to key=value assignments."""
    # Parse key=value specifications into a dictionary.
    model_cls = library.Album if album else library.Item
    fsets = {}
    for mod in mods:
        key, value = mod.split('=', 1)
        fsets[key] = model_cls._parse(key, value)

    # Get the items to modify.
    items, albums = _do_query(lib, query, album, False)
    objs = albums if album else items

    # Apply changes *temporarily*, preview them, and collect modified
    # objects.
    print_('Modifying %i %ss.' % (len(objs), 'album' if album else 'item'))
    changed = set()
    for obj in objs:
        for field, value in fsets.iteritems():
            obj[field] = value
        for field in dels:
            del obj[field]
        if ui.show_model_changes(obj):
            changed.add(obj)

    # Still something to do?
    if not changed:
        print_('No changes to make.')
        return

    # Confirm action.
    if confirm:
        extra = ' and write tags' if write else ''
        if not ui.input_yn('Really modify%s (Y/n)?' % extra):
            return

    # Apply changes to database.
    with lib.transaction():
        for obj in changed:
            if move:
                cur_path = obj.path
                if lib.directory in ancestry(cur_path): # In library?
                    log.debug('moving object %s' % cur_path)
                    obj.move()

            obj.store()

    # Apply tags if requested.
    if write:
        if album:
            changed_items = itertools.chain(*(a.items() for a in changed))
        else:
            changed_items = changed
        for item in changed_items:
            try:
                item.write()
            except library.FileOperationError as exc:
                log.error(exc)
示例#15
0
def read_albums(paths, resume):
    """A generator yielding all the albums (as sets of Items) found in
    the user-specified list of paths. `progress` specifies whether
    the resuming feature should be used. It may be True (resume if
    possible), False (never resume), or None (ask).
    """
    # Use absolute paths.
    paths = [library._normpath(path) for path in paths]

    # Check the user-specified directories.
    for path in paths:
        if not os.path.isdir(library._syspath(path)):
            raise ui.UserError('not a directory: ' + path)

    # Look for saved progress.
    progress = resume is not False
    if progress:
        resume_dirs = {}
        for path in paths:
            resume_dir = progress_get(path)
            if resume_dir:

                # Either accept immediately or prompt for input to decide.
                if resume:
                    do_resume = True
                    ui.print_('Resuming interrupted import of %s' % path)
                else:
                    do_resume = ui.input_yn("Import of the directory:\n%s"
                                            "\nwas interrupted. Resume (Y/n)?" %
                                            path)
                ui.print_()

                if do_resume:
                    resume_dirs[path] = resume_dir
                else:
                    # Clear progress; we're starting from the top.
                    progress_set(path, None)
    
    for toppath in paths:
        # Produce each path.
        if progress:
            resume_dir = resume_dirs.get(toppath)
        for path, items in autotag.albums_in_dir(os.path.expanduser(toppath)):
            if progress and resume_dir:
                # We're fast-forwarding to resume a previous tagging.
                if path == resume_dir:
                    # We've hit the last good path! Turn off the
                    # fast-forwarding.
                    resume_dir = None
                continue

            yield toppath, path, items

        # Indicate the directory is finished.
        yield toppath, DONE_SENTINEL, None
示例#16
0
    def ask_create(self, create=None):
        if not self.removable:
            return True
        if create is not None:
            return create

        msg = u"Collection at '{0}' does not exists. " \
              "Maybe you forgot to mount it.\n" \
              "Do you want to create the collection? (y/n)" \
              .format(displayable_path(self.directory))
        return input_yn(msg, require=True)
    def ask_create(self, create=None):
        if not self.removable:
            return True
        if create is not None:
            return create

        msg = u"Collection at '{0}' does not exists. " \
              "Maybe you forgot to mount it.\n" \
              "Do you want to create the collection? (y/n)" \
              .format(displayable_path(self.directory))
        return input_yn(msg, require=True)
示例#18
0
def modify_items(lib, mods, query, write, move, album, confirm):
    """Modifies matching items according to key=value assignments."""
    # Parse key=value specifications into a dictionary.
    fsets = {}
    for mod in mods:
        key, value = mod.split('=', 1)
        fsets[key] = _convert_type(key, value, album)

    # Get the items to modify.
    items, albums = _do_query(lib, query, album, False)
    objs = albums if album else items

    # Preview change.
    print_('Modifying %i %ss.' % (len(objs), 'album' if album else 'item'))
    for obj in objs:
        # Identify the changed object.
        ui.print_obj(obj, lib)

        # Show each change.
        for field, value in fsets.iteritems():
            _showdiff(field, obj.get(field), value)

    # Confirm.
    if confirm:
        extra = ' and write tags' if write else ''
        if not ui.input_yn('Really modify%s (Y/n)?' % extra):
            return

    # Apply changes to database.
    with lib.transaction():
        for obj in objs:
            for field, value in fsets.iteritems():
                obj[field] = value

            if move:
                cur_path = obj.item_dir() if album else obj.path
                if lib.directory in ancestry(cur_path):  # In library?
                    log.debug('moving object %s' % cur_path)
                    if album:
                        obj.move()
                    else:
                        lib.move(obj)

            obj.store()

    # Apply tags if requested.
    if write:
        if album:
            items = itertools.chain(*(a.items() for a in albums))
        for item in items:
            item.write()
示例#19
0
def modify_items(lib, mods, query, write, move, album, confirm):
    """Modifies matching items according to key=value assignments."""
    # Parse key=value specifications into a dictionary.
    fsets = {}
    for mod in mods:
        key, value = mod.split('=', 1)
        fsets[key] = _convert_type(key, value, album)

    # Get the items to modify.
    items, albums = _do_query(lib, query, album, False)
    objs = albums if album else items

    # Preview change.
    print_('Modifying %i %ss.' % (len(objs), 'album' if album else 'item'))
    for obj in objs:
        # Identify the changed object.
        ui.print_obj(obj, lib)

        # Show each change.
        for field, value in fsets.iteritems():
            _showdiff(field, obj.get(field), value)

    # Confirm.
    if confirm:
        extra = ' and write tags' if write else ''
        if not ui.input_yn('Really modify%s (Y/n)?' % extra):
            return

    # Apply changes to database.
    with lib.transaction():
        for obj in objs:
            for field, value in fsets.iteritems():
                obj[field] = value

            if move:
                cur_path = obj.item_dir() if album else obj.path
                if lib.directory in ancestry(cur_path): # In library?
                    log.debug('moving object %s' % cur_path)
                    if album:
                        obj.move()
                    else:
                        lib.move(obj)

            obj.store()

    # Apply tags if requested.
    if write:
        if album:
            items = itertools.chain(*(a.items() for a in albums))
        for item in items:
            item.write()
示例#20
0
    def update(self):
        if not self.query and not self.force_update:
            if not input_yn('Do you want to overwrite all '
                            'checksums in your database? (y/n)', require=True):
                return

        items = self.lib.items(self.query)
        total = len(items)

        def update(item):
            log.debug('updating checksum: {}'.format(item.path))
            set_checksum(item)

        self.execute_with_progress(update, items, msg='Updating checksums')
示例#21
0
文件: convert.py 项目: Smyds/beets
    def convert_func(self, lib, opts, args):
        dest = opts.dest or self.config['dest'].get()
        if not dest:
            raise ui.UserError(u'no convert destination set')
        dest = util.bytestring_path(dest)

        threads = opts.threads or self.config['threads'].get(int)

        path_formats = ui.get_path_formats(self.config['paths'] or None)

        fmt = opts.format or self.config['format'].as_str().lower()

        if opts.pretend is not None:
            pretend = opts.pretend
        else:
            pretend = self.config['pretend'].get(bool)

        if opts.album:
            albums = lib.albums(ui.decargs(args))
            items = [i for a in albums for i in a.items()]
            if not pretend:
                for a in albums:
                    ui.print_(format(a, u''))
        else:
            items = list(lib.items(ui.decargs(args)))
            if not pretend:
                for i in items:
                    ui.print_(format(i, u''))

        if not items:
            self._log.error(u'Empty query result.')
            return
        if not (pretend or opts.yes or ui.input_yn(u"Convert? (Y/n)")):
            return

        if opts.album and self.config['copy_album_art']:
            for album in albums:
                self.copy_album_art(album, dest, path_formats, pretend)

        convert = [self.convert_item(dest,
                                     opts.keep_new,
                                     path_formats,
                                     fmt,
                                     pretend)
                   for _ in range(threads)]
        pipe = util.pipeline.Pipeline([iter(items), convert])
        pipe.run_parallel()
示例#22
0
    def update(self):
        if not self.query and not self.force_update:
            if not input_yn(u'Do you want to overwrite all '
                            'checksums in your database? (y/n)', require=True):
                return

        items = self.lib.items(self.query)

        def update(item):
            log.debug(u'updating checksum: {}'
                      .format(displayable_path(item.path)))
            try:
                set_checksum(item)
            except IOError as exc:
                log.error(u'{} {}'.format(colorize('red', u'ERROR'), exc))

        self.execute_with_progress(update, items, msg=u'Updating checksums')
示例#23
0
def _confirm(objs, album):
    """Show the list of affected objects (items or albums) and confirm
    that the user wants to modify their artwork.

    `album` is a Boolean indicating whether these are albums (as opposed
    to items).
    """
    noun = u'album' if album else u'file'
    prompt = u'Modify artwork for {} {}{} (Y/n)?'.format(
        len(objs), noun, u's' if len(objs) > 1 else u'')

    # Show all the items or albums.
    for obj in objs:
        print_(format(obj))

    # Confirm with user.
    return ui.input_yn(prompt)
示例#24
0
    def update(self):
        if not self.query and not self.force_update:
            if not input_yn(u'Do you want to overwrite all '
                            'checksums in your database? (y/n)', require=True):
                return

        items = self.lib.items(self.query)

        def update(item):
            log.debug(u'updating checksum: {}'
                      .format(displayable_path(item.path)))
            try:
                set_checksum(item)
            except IOError as exc:
                log.error(u'{} {}'.format(colorize('red', u'ERROR'), exc))

        self.execute_with_progress(update, items, msg=u'Updating checksums')
示例#25
0
def convert_func(lib, config, opts, args):
    dest = opts.dest if opts.dest is not None else conf['dest']
    if not dest:
        raise ui.UserError('no convert destination set')
    threads = opts.threads if opts.threads is not None else conf['threads']

    ui.commands.list_items(lib, ui.decargs(args), opts.album, None, config)

    if not ui.input_yn("Convert? (Y/n)"):
        return

    if opts.album:
        items = (i for a in lib.albums(ui.decargs(args)) for i in a.items())
    else:
        items = lib.items(ui.decargs(args))
    convert = [convert_item(lib, dest) for i in range(threads)]
    pipe = util.pipeline.Pipeline([items, convert])
    pipe.run_parallel()
示例#26
0
def convert_func(lib, config, opts, args):
    dest = opts.dest if opts.dest is not None else conf['dest']
    if not dest:
        raise ui.UserError('no convert destination set')
    threads = opts.threads if opts.threads is not None else conf['threads']

    ui.commands.list_items(lib, ui.decargs(args), opts.album, None, config)

    if not ui.input_yn("Convert? (Y/n)"):
        return

    if opts.album:
        items = (i for a in lib.albums(ui.decargs(args)) for i in a.items())
    else:
        items = lib.items(ui.decargs(args))
    convert = [convert_item(lib, dest) for i in range(threads)]
    pipe = util.pipeline.Pipeline([items, convert])
    pipe.run_parallel()
示例#27
0
    def verify_import_integrity(self, session, task):
        integrity_errors = []
        if not task.items:
            return
        for item in task.items:
            try:
                verify_integrity(item)
            except IntegrityError as ex:
                integrity_errors.append(ex)

        if integrity_errors:
            log.warn(u'Warning: failed to verify integrity')
            for error in integrity_errors:
                log.warn(u'  {}: {}'.format(displayable_path(item.path), error))
            if beets.config['import']['quiet'] \
               or input_yn(u'Do you want to skip this album (Y/n)'):
                log.info(u'Skipping.')
                task.choice_flag = importer.action.SKIP
示例#28
0
    def import_task_choice_listener(self, session, task):
        if task.apply:
            if config['import']['quiet'].get():
                return

            changes = self.show_changes(session.lib, task)

            # Only prompt when timid
            if 'timid' in self.config:
                timid = self.config['timid'].get(bool)
            else:
                timid = config['import']['timid'].get()

            if not changes or not timid:
                return

            if not ui.input_yn(u'Continue to apply these changes (Y/n)?'):
                task.set_choice(importer.action.SKIP)
示例#29
0
文件: convert.py 项目: m-urban/beets
    def convert_func(self, lib, opts, args):
        if not opts.dest:
            opts.dest = self.config['dest'].get()
        if not opts.dest:
            raise ui.UserError('no convert destination set')
        opts.dest = util.bytestring_path(opts.dest)

        if not opts.threads:
            opts.threads = self.config['threads'].get(int)

        if self.config['paths']:
            path_formats = ui.get_path_formats(self.config['paths'])
        else:
            path_formats = ui.get_path_formats()

        if not opts.format:
            opts.format = self.config['format'].get(unicode).lower()

        pretend = opts.pretend if opts.pretend is not None else \
            self.config['pretend'].get(bool)

        if not pretend:
            ui.commands.list_items(lib, ui.decargs(args), opts.album)

            if not (opts.yes or ui.input_yn("Convert? (Y/n)")):
                return

        if opts.album:
            albums = lib.albums(ui.decargs(args))
            items = (i for a in albums for i in a.items())
            if self.config['copy_album_art']:
                for album in albums:
                    self.copy_album_art(album, opts.dest, path_formats,
                                        pretend)
        else:
            items = iter(lib.items(ui.decargs(args)))
        convert = [self.convert_item(opts.dest,
                                     opts.keep_new,
                                     path_formats,
                                     opts.format,
                                     pretend)
                   for _ in range(opts.threads)]
        pipe = util.pipeline.Pipeline([items, convert])
        pipe.run_parallel()
示例#30
0
    def convert_func(self, lib, opts, args):
        if not opts.dest:
            opts.dest = self.config['dest'].get()
        if not opts.dest:
            raise ui.UserError('no convert destination set')
        opts.dest = util.bytestring_path(opts.dest)

        if not opts.threads:
            opts.threads = self.config['threads'].get(int)

        if self.config['paths']:
            path_formats = ui.get_path_formats(self.config['paths'])
        else:
            path_formats = ui.get_path_formats()

        if not opts.format:
            opts.format = self.config['format'].get(unicode).lower()

        pretend = opts.pretend if opts.pretend is not None else \
            self.config['pretend'].get(bool)

        if not pretend:
            ui.commands.list_items(lib, ui.decargs(args), opts.album)

            if not (opts.yes or ui.input_yn("Convert? (Y/n)")):
                return

        if opts.album:
            albums = lib.albums(ui.decargs(args))
            items = (i for a in albums for i in a.items())
            if self.config['copy_album_art']:
                for album in albums:
                    self.copy_album_art(album, opts.dest, path_formats,
                                        pretend)
        else:
            items = iter(lib.items(ui.decargs(args)))
        convert = [self.convert_item(opts.dest,
                                     opts.keep_new,
                                     path_formats,
                                     opts.format,
                                     pretend)
                   for _ in range(opts.threads)]
        pipe = util.pipeline.Pipeline([items, convert])
        pipe.run_parallel()
示例#31
0
    def fix(self, ask=True):
        items = list(self.lib.items(self.query))
        failed = []

        def check(item):
            try:
                if 'checksum' in item:
                    verify_checksum(item)
                fixer = IntegrityChecker.fixer(item)
                if fixer:
                    fixer.check(item)
                    log.debug(u'{}: {}'.format(colorize('green', u'OK'),
                                               displayable_path(item.path)))
            except IntegrityError:
                failed.append(item)
            except ChecksumError:
                log.error(u'{}: {}'.format(colorize('red', u'FAILED checksum'),
                                           displayable_path(item.path)))
            except IOError as exc:
                log.error(u'{} {}'.format(colorize('red', u'ERROR'), exc))

        self.execute_with_progress(check, items, msg=u'Verifying integrity')

        if not failed:
            self.log(u'No MP3 files to fix')
            return

        for item in failed:
            log.info(displayable_path(item.path))

        if ask and not input_yn(u'Do you want to fix these files? {} (y/n)',
                                require=True):
            return

        def fix(item):
            fixer = IntegrityChecker.fixer(item)
            if fixer:
                fixer.fix(item)
                log.debug(u'{}: {}'.format(colorize('green', u'FIXED'),
                                           displayable_path(item.path)))
                set_checksum(item)

        self.execute_with_progress(fix, failed, msg=u'Fixing files')
示例#32
0
    def verify_import_integrity(self, session, task):
        integrity_errors = []
        if not task.items:
            return
        for item in task.items:
            try:
                verify_integrity(item)
            except IntegrityError as ex:
                integrity_errors.append(ex)

        if integrity_errors:
            log.warn(u'Warning: failed to verify integrity')
            for error in integrity_errors:
                log.warn(u'  {}: {}'.format(displayable_path(item.path),
                                            error))
            if beets.config['import']['quiet'] \
               or input_yn(u'Do you want to skip this album (Y/n)'):
                log.info(u'Skipping.')
                task.choice_flag = importer.action.SKIP
示例#33
0
    def fix(self, ask=True):
        items = list(self.lib.items(self.query))
        failed = []

        def check(item):
            try:
                if 'checksum' in item:
                    verify_checksum(item)
                fixer = IntegrityChecker.fixer(item)
                if fixer:
                    fixer.check(item)
                    log.debug(u'{}: {}'.format(colorize('green', u'OK'),
                                               displayable_path(item.path)))
            except IntegrityError:
                failed.append(item)
            except ChecksumError:
                log.error(u'{}: {}'.format(colorize('red', u'FAILED checksum'),
                                           displayable_path(item.path)))
            except IOError as exc:
                log.error(u'{} {}'.format(colorize('red', u'ERROR'), exc))

        self.execute_with_progress(check, items, msg=u'Verifying integrity')

        if not failed:
            self.log(u'No MP3 files to fix')
            return

        for item in failed:
            log.info(displayable_path(item.path))

        if ask and not input_yn(u'Do you want to fix these files? {} (y/n)',
                                require=True):
            return

        def fix(item):
            fixer = IntegrityChecker.fixer(item)
            if fixer:
                fixer.fix(item)
                log.debug(u'{}: {}'.format(colorize('green', u'FIXED'),
                                           displayable_path(item.path)))
                set_checksum(item)

        self.execute_with_progress(fix, failed, msg=u'Fixing files')
示例#34
0
def read_albums(paths):
    """A generator yielding all the albums (as sets of Items) found in
    the user-specified list of paths.
    """
    # Use absolute paths.
    paths = [library._normpath(path) for path in paths]

    # Check the user-specified directories.
    for path in paths:
        if not os.path.isdir(library._syspath(path)):
            raise ui.UserError('not a directory: ' + path)
    # Look for saved progress.
    resume_dirs = {}
    for path in paths:
        resume_dir = progress_get(path)
        if resume_dir:
            resume = ui.input_yn("Import of the directory:\n%s"
                                 "\nwas interrupted. Resume (Y/n)? " %
                                 path)
            if resume:
                resume_dirs[path] = resume_dir
            else:
                # Clear progress; we're starting from the top.
                progress_set(path, None)
            ui.print_()
    
    for toppath in paths:
        # Produce each path.
        resume_dir = resume_dirs.get(toppath)
        for path, items in autotag.albums_in_dir(os.path.expanduser(toppath)):
            if resume_dir:
                # We're fast-forwarding to resume a previous tagging.
                if path == resume_dir:
                    # We've hit the last good path! Turn off the
                    # fast-forwarding.
                    resume_dir = None
                continue

            yield toppath, path, items

        # Indicate the directory is finished.
        yield toppath, DONE_SENTINEL, None
示例#35
0
def _confirm(objs, album):
    """Show the list of affected objects (items or albums) and confirm
    that the user wants to modify their artwork.

    `album` is a Boolean indicating whether these are albums (as opposed
    to items).
    """
    noun = u'album' if album else u'file'
    prompt = u'Modify artwork for {} {}{} (Y/n)?'.format(
        len(objs),
        noun,
        u's' if len(objs) > 1 else u''
    )

    # Show all the items or albums.
    for obj in objs:
        print_(format(obj))

    # Confirm with user.
    return ui.input_yn(prompt)
示例#36
0
def remove_items(lib, query, album, delete=False):
    """Remove items matching query from lib. If album, then match and
    remove whole albums. If delete, also remove files from disk.
    """
    # Get the matching items.
    if album:
        albums = list(lib.albums(query=query))
        items = []
        for al in albums:
            items += al.items()
    else:
        items = list(lib.items(query=query))

    if not items:
        print_('No matching items found.')
        return

    # Show all the items.
    for item in items:
        print_(item.artist + ' - ' + item.album + ' - ' + item.title)

    # Confirm with user.
    print_()
    if delete:
        prompt = 'Really DELETE %i files (y/n)?' % len(items)
    else:
        prompt = 'Really remove %i items from the library (y/n)?' % \
                 len(items)
    if not ui.input_yn(prompt, True):
        return

    # Remove (and possibly delete) items.
    if album:
        for al in albums:
            al.remove(delete)
    else:
        for item in items:
            lib.remove(item, delete)

    lib.save()
示例#37
0
文件: convert.py 项目: KumaraKL/beets
def convert_func(lib, opts, args):
    if not opts.dest:
        opts.dest = config['convert']['dest'].get()
    if not opts.dest:
        raise ui.UserError('no convert destination set')
    opts.dest = util.bytestring_path(opts.dest)

    if not opts.threads:
        opts.threads = config['convert']['threads'].get(int)

    if config['convert']['paths']:
        path_formats = ui.get_path_formats(config['convert']['paths'])
    else:
        path_formats = ui.get_path_formats()

    if not opts.format:
        opts.format = config['convert']['format'].get(unicode).lower()

    command, ext = get_format(opts.format)

    ui.commands.list_items(lib, ui.decargs(args), opts.album, None)

    if not ui.input_yn("Convert? (Y/n)"):
        return

    if opts.album:
        items = (i for a in lib.albums(ui.decargs(args)) for i in a.items())
    else:
        items = iter(lib.items(ui.decargs(args)))
    convert_stages = []
    for i in range(opts.threads):
        convert_stages.append(
            convert_item(opts.dest, opts.keep_new, path_formats, command, ext)
        )
    pipe = util.pipeline.Pipeline([items, convert_stages])
    pipe.run_parallel()
示例#38
0
    def edit_objects(self, objs, fields):
        """Dump a set of Model objects to a file as text, ask the user
        to edit it, and apply any changes to the objects.

        Return a boolean indicating whether the edit succeeded.
        """
        # Get the content to edit as raw data structures.
        old_data = [flatten(o, fields) for o in objs]

        # Set up a temporary file with the initial data for editing.
        new = NamedTemporaryFile(suffix='.yaml', delete=False)
        old_str = dump(old_data)
        new.write(old_str)
        new.close()

        # Loop until we have parseable data and the user confirms.
        try:
            while True:
                # Ask the user to edit the data.
                edit(new.name)

                # Read the data back after editing and check whether anything
                # changed.
                with open(new.name) as f:
                    new_str = f.read()
                if new_str == old_str:
                    ui.print_("No changes; aborting.")
                    return False

                # Parse the updated data.
                try:
                    new_data = load(new_str)
                except ParseError as e:
                    ui.print_("Could not read data: {}".format(e))
                    if ui.input_yn("Edit again to fix? (Y/n)", True):
                        continue
                    else:
                        return False

                # Show the changes.
                self.apply_data(objs, old_data, new_data)
                changed = False
                for obj in objs:
                    changed |= ui.show_model_changes(obj)
                if not changed:
                    ui.print_('No changes to apply.')
                    return False

                # Confirm the changes.
                choice = ui.input_options(
                    ('continue Editing', 'apply', 'cancel'))
                if choice == 'a':  # Apply.
                    return True
                elif choice == 'c':  # Cancel.
                    return False
                elif choice == 'e':  # Keep editing.
                    # Reset the temporary changes to the objects.
                    for obj in objs:
                        obj.read()
                    continue

        # Remove the temporary file before returning.
        finally:
            os.remove(new.name)
示例#39
0
 def should_resume(self, path):
     return ui.input_yn(u"Import of the directory:\n{0}\n"
                        "was interrupted. Resume (Y/n)?".format(
                            displayable_path(path)))
示例#40
0
文件: commands.py 项目: encukou/beets
def should_resume(config, path):
    return ui.input_yn("Import of the directory:\n%s"
                       "\nwas interrupted. Resume (Y/n)?" % path)
示例#41
0
 def suggest_removal(self, item):
     """Prompts the user to delete the original path the item was imported from."""
     if not item[
             'source_path'] or item.mb_albumid in self.stop_suggestions_for_albums:
         return
     if os.path.isdir(item['source_path']):
         # We ask the user whether they'd like to delete the item's source directory
         delete = input_yn(
             "The item:\n{path}\nis originated in the directory:\n{source}\n"
             "Would you like to delete the source directory of this item?".
             format(path=colorize_text("text_warning",
                                       item.path.decode('utf-8')),
                    source=colorize_text(
                        "text_warning",
                        item['source_path'].decode('utf-8'))),
             require=True)
         if delete:
             self._log.info(
                 "Deleting the item's source which is a directory: %s",
                 item['source_path'])
             rmtree(item['source_path'])
     elif os.path.isfile(item['source_path']):
         # We ask the user whether they'd like to delete the item's source directory
         print("The item:\n{path}\nis originated in from:\n{source}\n"
               "What would you like to do?".format(
                   path=colorize_text("text_warning",
                                      item.path.decode('utf-8')),
                   source=colorize_text(
                       "text_warning",
                       item['source_path'].decode('utf-8'))))
         resp = input_options(
             [
                 "Delete the item's source",
                 "Recursively delete the source's directory", "do Nothing",
                 "do nothing and Stop suggesting to delete items from this album"
             ],
             require=True,
         )
         if resp == 'd':
             self._log.info("Deleting the item's source file: %s",
                            item['source_path'])
             os.remove(item['source_path'])
         elif resp == 'r':
             source_dir = os.path.dirname(item['source_path'])
             self._log.info(
                 "Searching for other items with a source_path attr containing: %s",
                 source_dir)
             # NOTE: I'm not sure why, but we need to escape it twice otherwise the search fails
             escaped_source_dir = re.escape(
                 re.escape(source_dir.decode("utf-8")))
             source_dir_query = "source_path::^{}/*".format(
                 escaped_source_dir)
             print(
                 "Doing so will delete the following items' sources as well:"
             )
             for searched_item in item._db.items(source_dir_query):
                 print(
                     colorize_text("text_warning",
                                   searched_item['path'].decode('utf-8')))
             print("Would you like to continue?")
             continue_resp = input_options(
                 ["Yes", "delete None", "delete just the File"],
                 require=False,  # Yes is the a default
             )
             if continue_resp == 'y':
                 self._log.info("Deleting the item's source directory: %s",
                                source_dir)
                 rmtree(source_dir)
             elif continue_resp == 'n':
                 self._log.info("doing nothing - aborting hook function")
                 return
             elif continue_resp == 'f':
                 self._log.info(
                     "removing just the item's original source: %s",
                     item['source_path'])
                 os.remove(item['source_path'])
         elif resp == 's':
             self.stop_suggestions_for_albums.append(item.mb_albumid)
         else:
             self._log.info("Doing nothing")
示例#42
0
文件: edit.py 项目: MatijaB/beets
    def edit_objects(self, objs, fields):
        """Dump a set of Model objects to a file as text, ask the user
        to edit it, and apply any changes to the objects.

        Return a boolean indicating whether the edit succeeded.
        """
        # Get the content to edit as raw data structures.
        old_data = [flatten(o, fields) for o in objs]

        # Set up a temporary file with the initial data for editing.
        new = NamedTemporaryFile(suffix=".yaml", delete=False)
        old_str = dump(old_data)
        new.write(old_str)
        new.close()

        # Loop until we have parseable data and the user confirms.
        try:
            while True:
                # Ask the user to edit the data.
                edit(new.name)

                # Read the data back after editing and check whether anything
                # changed.
                with open(new.name) as f:
                    new_str = f.read()
                if new_str == old_str:
                    ui.print_("No changes; aborting.")
                    return False

                # Parse the updated data.
                try:
                    new_data = load(new_str)
                except ParseError as e:
                    ui.print_("Could not read data: {}".format(e))
                    if ui.input_yn("Edit again to fix? (Y/n)", True):
                        continue
                    else:
                        return False

                # Show the changes.
                self.apply_data(objs, old_data, new_data)
                changed = False
                for obj in objs:
                    changed |= ui.show_model_changes(obj)
                if not changed:
                    ui.print_("No changes to apply.")
                    return False

                # Confirm the changes.
                choice = ui.input_options(("continue Editing", "apply", "cancel"))
                if choice == "a":  # Apply.
                    return True
                elif choice == "c":  # Cancel.
                    return False
                elif choice == "e":  # Keep editing.
                    # Reset the temporary changes to the objects.
                    for obj in objs:
                        obj.read()
                    continue

        # Remove the temporary file before returning.
        finally:
            os.remove(new.name)
示例#43
0
def should_resume(config, path):
    return ui.input_yn("Import of the directory:\n%s"
                       "\nwas interrupted. Resume (Y/n)?" % path)
示例#44
0
    def edit_objects(self, objs, fields):
        """Dump a set of Model objects to a file as text, ask the user
        to edit it, and apply any changes to the objects.

        Return a boolean indicating whether the edit succeeded.
        """
        # Get the content to edit as raw data structures.
        old_data = [flatten(o, fields) for o in objs]

        # Set up a temporary file with the initial data for editing.
        if six.PY2:
            new = NamedTemporaryFile(mode='w', suffix='.yaml', delete=False)
        else:
            new = NamedTemporaryFile(mode='w', suffix='.yaml', delete=False,
                                     encoding='utf-8')
        old_str = dump(old_data)
        new.write(old_str)
        if six.PY2:
            old_str = old_str.decode('utf-8')
        new.close()

        # Loop until we have parseable data and the user confirms.
        try:
            while True:
                # Ask the user to edit the data.
                edit(new.name, self._log)

                # Read the data back after editing and check whether anything
                # changed.
                with codecs.open(new.name, encoding='utf-8') as f:
                    new_str = f.read()
                if new_str == old_str:
                    ui.print_(u"No changes; aborting.")
                    return False

                # Parse the updated data.
                try:
                    new_data = load(new_str)
                except ParseError as e:
                    ui.print_(u"Could not read data: {}".format(e))
                    if ui.input_yn(u"Edit again to fix? (Y/n)", True):
                        continue
                    else:
                        return False

                # Show the changes.
                # If the objects are not on the DB yet, we need a copy of their
                # original state for show_model_changes.
                objs_old = [obj.copy() if obj.id < 0 else None
                            for obj in objs]
                self.apply_data(objs, old_data, new_data)
                changed = False
                for obj, obj_old in zip(objs, objs_old):
                    changed |= ui.show_model_changes(obj, obj_old)
                if not changed:
                    ui.print_(u'No changes to apply.')
                    return False

                # Confirm the changes.
                choice = ui.input_options(
                    (u'continue Editing', u'apply', u'cancel')
                )
                if choice == u'a':  # Apply.
                    return True
                elif choice == u'c':  # Cancel.
                    return False
                elif choice == u'e':  # Keep editing.
                    # Reset the temporary changes to the objects. I we have a
                    # copy from above, use that, else reload from the database.
                    objs = [(old_obj or obj)
                            for old_obj, obj in zip(objs_old, objs)]
                    for obj in objs:
                        if not obj.id < 0:
                            obj.load()
                    continue

        # Remove the temporary file before returning.
        finally:
            os.remove(new.name)
示例#45
0
 def zero_fields(lib, opts, args):
     if not decargs(args) and not input_yn(
             u"Remove fields for all items? (Y/n)", True):
         return
     for item in lib.items(decargs(args)):
         self.process_item(item)
示例#46
0
    def edit_objects(self, objs, fields):
        """Dump a set of Model objects to a file as text, ask the user
        to edit it, and apply any changes to the objects.

        Return a boolean indicating whether the edit succeeded.
        """
        # Get the content to edit as raw data structures.
        old_data = [flatten(o, fields) for o in objs]

        # Set up a temporary file with the initial data for editing.
        if six.PY2:
            new = NamedTemporaryFile(mode='w', suffix='.yaml', delete=False)
        else:
            new = NamedTemporaryFile(mode='w',
                                     suffix='.yaml',
                                     delete=False,
                                     encoding='utf-8')
        old_str = dump(old_data)
        new.write(old_str)
        if six.PY2:
            old_str = old_str.decode('utf-8')
        new.close()

        # Loop until we have parseable data and the user confirms.
        try:
            while True:
                # Ask the user to edit the data.
                edit(new.name, self._log)

                # Read the data back after editing and check whether anything
                # changed.
                with codecs.open(new.name, encoding='utf-8') as f:
                    new_str = f.read()
                if new_str == old_str:
                    ui.print_(u"No changes; aborting.")
                    return False

                # Parse the updated data.
                try:
                    new_data = load(new_str)
                except ParseError as e:
                    ui.print_(u"Could not read data: {}".format(e))
                    if ui.input_yn(u"Edit again to fix? (Y/n)", True):
                        continue
                    else:
                        return False

                # Show the changes.
                # If the objects are not on the DB yet, we need a copy of their
                # original state for show_model_changes.
                objs_old = [
                    deepcopy(obj) if not obj._db else None for obj in objs
                ]
                self.apply_data(objs, old_data, new_data)
                changed = False
                for obj, obj_old in zip(objs, objs_old):
                    changed |= ui.show_model_changes(obj, obj_old)
                if not changed:
                    ui.print_(u'No changes to apply.')
                    return False

                # Confirm the changes.
                choice = ui.input_options(
                    (u'continue Editing', u'apply', u'cancel'))
                if choice == u'a':  # Apply.
                    return True
                elif choice == u'c':  # Cancel.
                    return False
                elif choice == u'e':  # Keep editing.
                    # Reset the temporary changes to the objects.
                    for obj in objs:
                        obj.read()
                    continue

        # Remove the temporary file before returning.
        finally:
            os.remove(new.name)
示例#47
0
文件: commands.py 项目: jlefley/beets
 def should_resume(self, path):
     return ui.input_yn(u"Import of the directory:\n{0}\n"
                        "was interrupted. Resume (Y/n)?"
                        .format(displayable_path(path)))