Example #1
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.
    if album:
        allowed_keys = library.ALBUM_KEYS
    else:
        allowed_keys = library.ITEM_KEYS_WRITABLE + ['added']
    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] = _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():
            curval = getattr(obj, field)
            _showdiff(field, curval, 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():
                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()
Example #2
0
def _print_and_apply_changes(lib, item, old_data, move, pretend, write):
    """Apply changes to an Item and preview them in the console. Return
    a boolean indicating whether any changes were made.
    """
    changes = {}
    for key in library.ITEM_KEYS_META:
        if key in item._dirty:
            changes[key] = old_data[key], getattr(item, key)
    if not changes:
        return False

    # Something changed.
    ui.print_obj(item, lib)
    for key, (oldval, newval) in changes.iteritems():
        ui.commands._showdiff(key, oldval, newval)

    # If we're just pretending, then don't move or save.
    if not pretend:
        # Move the item if it's in the library.
        if move and lib.directory in util.ancestry(item.path):
            item.move(with_album=False)

        if write:
            try:
                item.write()
            except Exception as exc:
                log.error(u'could not sync {0}: {1}'.format(
                    util.displayable_path(item.path), exc))
                return False
        item.store()

    return True
Example #3
0
def _print_and_apply_changes(lib, item, move, pretend, write):
    """Apply changes to an Item and preview them in the console. Return
    a boolean indicating whether any changes were made.
    """
    changes = {}
    for key in library.ITEM_KEYS_META:
        if item.dirty[key]:
            changes[key] = item.old_data[key], getattr(item, key)
    if not changes:
        return False

    # Something changed.
    ui.print_obj(item, lib)
    for key, (oldval, newval) in changes.iteritems():
        ui.commands._showdiff(key, oldval, newval)

    # If we're just pretending, then don't move or save.
    if not pretend:
        # Move the item if it's in the library.
        if move and lib.directory in util.ancestry(item.path):
            lib.move(item, with_album=False)

        if write:
            try:
                item.write()
            except Exception as exc:
                log.error(u'could not sync {0}: {1}'.format(
                    util.displayable_path(item.path), exc))
                return False
        lib.store(item)

    return True
Example #4
0
def _process_item(item,
                  lib,
                  copy=False,
                  move=False,
                  delete=False,
                  tag=False,
                  format=None):
    """Process Item `item` in `lib`.
    """
    if copy:
        item.move_file(dest=copy, copy=True)
        item.store()
    if move:
        item.move_file(dest=move, copy=False)
        item.store()
    if delete:
        item.remove(delete=True)
    if tag:
        try:
            k, v = tag.split('=')
        except:
            raise UserError('%s: can\'t parse k=v tag: %s' % (PLUGIN, tag))
        setattr(k, v)
        item.store()
    print_obj(item, lib, fmt=format)
Example #5
0
def similar(lib, src_item, threshold=0.15, fmt='${difference}: ${path}'):
    for item in lib.items():
        if item.path != src_item.path:
            d = diff(item, src_item)
            if d < threshold:
                s = fmt.replace('${difference}', '{:2.2f}'.format(d))
                ui.print_obj(item, lib, s)
Example #6
0
def remove_items(lib, query, album, delete, config):
    """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, config)

    # 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)
def dupl_finder(lib, opts, args):
    """Lists and possibly deletes duplicates
    """
    opts = vars(opts)

    # handle special printing formats
    if opts["output_format"]:
        fmt = opts["output_format"]
    else:
        fmt = '$albumartist - $album - $title'
    if opts["output_count"]:
        fmt += ": ({0})"

    key_list = gen_keylist(opts)
    if len(key_list) == 0:
        # no option set, setting default one
        key_list = ['title', 'artist', 'album']

    res = check_key(key_list, lib.items(query = args))
    for key, match_list in res.iteritems():
        num = len(match_list)
        if num > 1:
            # found duplicates
            if opts["output_count"]:
                print_obj(match_list[0], lib, fmt=fmt.format(num))
            else:
                for match in match_list:
                    print_obj(match, lib, fmt=fmt.format(num))
            print ""
Example #8
0
File: fuzzy.py Project: flz/beets
def fuzzy_list(lib, opts, args):
    query = decargs(args)
    query = ' '.join(query).lower()
    queryMatcher = difflib.SequenceMatcher(b=query)

    if opts.threshold is not None:
        threshold = float(opts.threshold)
    else:
        threshold = config['fuzzy']['threshold'].as_number()

    if opts.path:
        fmt = '$path'
    else:
        fmt = opts.format
    template = Template(fmt) if fmt else None

    if opts.album:
        objs = lib.albums()
    else:
        objs = lib.items()

    items = filter(lambda i: is_match(queryMatcher, i, album=opts.album,
                                      threshold=threshold), objs)

    for item in items:
        print_obj(item, lib, template)
        if opts.verbose:
            print(is_match(queryMatcher, item,
                           album=opts.album, verbose=True)[1])
Example #9
0
def fuzzy_list(lib, config, opts, args):
    query = decargs(args)
    query = ' '.join(query).lower()
    queryMatcher = difflib.SequenceMatcher(b=query)

    if opts.threshold is not None:
        threshold = float(opts.threshold)
    else:
        threshold = float(conf['threshold'])

    if opts.path:
        fmt = '$path'
    else:
        fmt = opts.format
    template = Template(fmt) if fmt else None

    if opts.album:
        objs = lib.albums()
    else:
        objs = lib.items()

    items = filter(lambda i: is_match(queryMatcher, i, album=opts.album,
                                      threshold=threshold), objs)

    for item in items:
        print_obj(item, lib, config, template)
        if opts.verbose:
            print(is_match(queryMatcher, i, album=opts.album, verbose=True)[1])
Example #10
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.
    if album:
        allowed_keys = library.ALBUM_KEYS
    else:
        allowed_keys = library.ITEM_KEYS_WRITABLE + ['added']
    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] = _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():
            curval = getattr(obj, field)
            _showdiff(field, curval, 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():
                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()
Example #11
0
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():
        if album:
            for al in albums:
                al.remove(delete)
        else:
            for item in items:
                lib.remove(item, delete)
Example #12
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.
    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()
Example #13
0
def list_items(lib, query, album, fmt):
    """Print out items in lib matching query. If album, then search for
    albums instead of single items.
    """
    tmpl = Template(ui._pick_format(album, fmt))
    if album:
        for album in lib.albums(query):
            ui.print_obj(album, lib, tmpl)
    else:
        for item in lib.items(query):
            ui.print_obj(item, lib, tmpl)
Example #14
0
def list_items(lib, query, album, fmt, config):
    """Print out items in lib matching query. If album, then search for
    albums instead of single items.
    """
    tmpl = Template(fmt) if fmt else Template(ui._pick_format(config, album))
    if album:
        for album in lib.albums(query):
            ui.print_obj(album, lib, config, tmpl)
    else:
        for item in lib.items(query):
            ui.print_obj(item, lib, config, tmpl)
Example #15
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()
Example #16
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()
Example #17
0
def random_item(lib, config, opts, args):
    query = decargs(args)
    if opts.path:
        fmt = '$path'
    else:
        fmt = opts.format
    template = Template(fmt) if fmt else None

    if opts.album:
        objs = list(lib.albums(query=query))
    else:
        objs = list(lib.items(query=query))
    number = min(len(objs), opts.number)
    objs = random.sample(objs, number)

    for item in objs:
        print_obj(item, lib, config, template)
Example #18
0
File: random.py Project: flz/beets
def random_item(lib, opts, args):
    query = decargs(args)
    if opts.path:
        fmt = '$path'
    else:
        fmt = opts.format
    template = Template(fmt) if fmt else None

    if opts.album:
        objs = list(lib.albums(query=query))
    else:
        objs = list(lib.items(query=query))
    number = min(len(objs), opts.number)
    objs = random.sample(objs, number)

    for item in objs:
        print_obj(item, lib, template)
Example #19
0
def write_items(lib, query, pretend):
    """Write tag information from the database to the respective files
    in the filesystem.
    """
    items, albums = _do_query(lib, query, False, False)

    for item in items:
        # Item deleted?
        if not os.path.exists(syspath(item.path)):
            log.info(u'missing file: {0}'.format(
                util.displayable_path(item.path)
            ))
            continue

        # Get an Item object reflecting the "clean" (on-disk) state.
        try:
            clean_item = library.Item.from_path(item.path)
        except Exception as exc:
            log.error(u'error reading {0}: {1}'.format(
                displayable_path(item.path), exc
            ))
            continue

        # Get the keys that have changed between the version.
        changed = set()
        for key in library.ITEM_KEYS_META:
            if item[key] != clean_item[key]:
                changed.add(key)

        # Did anything change?
        if changed:
            ui.print_obj(item, lib)
            for key in changed:
                _showdiff(key, clean_item[key], item[key])

            # Actually write the tags.
            if not pretend:
                try:
                    item.write()
                except Exception as exc:
                    log.error(u'could not write {0}: {1}'.format(
                        util.displayable_path(item.path), exc
                    ))
                    continue
Example #20
0
def random_item(lib, opts, args):
    query = decargs(args)
    if opts.path:
        fmt = '$path'
    else:
        fmt = opts.format
    template = Template(fmt) if fmt else None

    if opts.album:
        objs = list(lib.albums(query=query))
    else:
        objs = list(lib.items(query=query))

    if opts.equal_chance:
        # Group the objects by artist so we can sample from them.
        key = attrgetter('albumartist')
        objs.sort(key=key)
        objs_by_artists = {}
        for artist, v in groupby(objs, key):
            objs_by_artists[artist] = list(v)

        objs = []
        for _ in range(opts.number):
            # Terminate early if we're out of objects to select.
            if not objs_by_artists:
                break

            # Choose an artist and an object for that artist, removing
            # this choice from the pool.
            artist = random.choice(objs_by_artists.keys())
            objs_from_artist = objs_by_artists[artist]
            i = random.randint(0, len(objs_from_artist) - 1)
            objs.append(objs_from_artist.pop(i))

            # Remove the artist if we've used up all of its objects.
            if not objs_from_artist:
                del objs_by_artists[artist]

    else:
        number = min(len(objs), opts.number)
        objs = random.sample(objs, number)

    for item in objs:
        print_obj(item, lib, template)
Example #21
0
def _process_item(item, lib, copy=False, move=False, delete=False,
                  tag=False, format=None):
    """Process Item `item` in `lib`.
    """
    if copy:
        item.move(basedir=copy, copy=True)
        item.store()
    if move:
        item.move(basedir=move, copy=False)
        item.store()
    if delete:
        item.remove(delete=True)
    if tag:
        try:
            k, v = tag.split('=')
        except:
            raise UserError('%s: can\'t parse k=v tag: %s' % (PLUGIN, tag))
        setattr(k, v)
        item.store()
    print_obj(item, lib, fmt=format)
Example #22
0
def write_items(lib, query, pretend):
    """Write tag information from the database to the respective files
    in the filesystem.
    """
    items, albums = _do_query(lib, query, False, False)

    for item in items:
        # Item deleted?
        if not os.path.exists(syspath(item.path)):
            log.info(u'missing file: {0}'.format(
                util.displayable_path(item.path)))
            continue

        # Get an Item object reflecting the "clean" (on-disk) state.
        try:
            clean_item = library.Item.from_path(item.path)
        except Exception as exc:
            log.error(u'error reading {0}: {1}'.format(
                displayable_path(item.path), exc))
            continue

        # Get the keys that have changed between the version.
        changed = set()
        for key in library.ITEM_KEYS_META:
            if item[key] != clean_item[key]:
                changed.add(key)

        # Did anything change?
        if changed:
            ui.print_obj(item, lib)
            for key in changed:
                _showdiff(key, clean_item[key], item[key])

            # Actually write the tags.
            if not pretend:
                try:
                    item.write()
                except Exception as exc:
                    log.error(u'could not write {0}: {1}'.format(
                        util.displayable_path(item.path), exc))
                    continue
Example #23
0
        def _miss(lib, opts, args):
            self.config.set_args(opts)
            fmt = self.config['format'].get()
            count = self.config['count'].get()
            total = self.config['total'].get()

            albums = lib.albums(decargs(args))
            if total:
                print(sum([_missing_count(a) for a in albums]))
                return

            for album in albums:
                if count:
                    missing = _missing_count(album)
                    if missing:
                        fmt = "$album: {}".format(missing)
                        print_obj(album, lib, fmt=fmt)
                    continue

                for item in _missing(album):
                    print_obj(item, lib, fmt=fmt)
Example #24
0
def random_item(lib, opts, args):
    query = decargs(args)
    if opts.path:
        fmt = '$path'
    else:
        fmt = opts.format
    template = Template(fmt) if fmt else None

    if opts.album:
        objs = list(lib.albums(query=query))
    else:
        objs = list(lib.items(query=query))

    if opts.equal_chance:
        key = attrgetter('albumartist')
        objs.sort(key=key)

        # {artists: objects}
        objs_by_artists = {artist: list(v) for artist, v in groupby(objs, key)}
        artists = objs_by_artists.keys()

        # {artist: count}
        selected_artists = collections.defaultdict(int)
        for _ in range(opts.number):
            selected_artists[random.choice(artists)] += 1

        objs = []
        for artist, count in selected_artists.items():
            objs_from_artist = objs_by_artists[artist]
            number = min(count, len(objs_from_artist))
            objs.extend(random.sample(objs_from_artist, number))

    else:
        number = min(len(objs), opts.number)
        objs = random.sample(objs, number)

    for item in objs:
        print_obj(item, lib, template)
Example #25
0
        def _dup(lib, opts, args):
            self.config.set_args(opts)
            fmt = self.config['format'].get()
            count = self.config['count'].get()
            album = self.config['album'].get()
            full = self.config['full'].get()

            if album:
                items = lib.albums(decargs(args))
            else:
                items = lib.items(decargs(args))

            # Default format string for count mode.
            if count and not fmt:
                if album:
                    fmt = '$albumartist - $album'
                else:
                    fmt = '$albumartist - $album - $title'
                fmt += ': {}'

            for obj_id, obj_count, objs in _duplicates(items, full):
                if obj_id:  # Skip empty IDs.
                    for o in objs:
                        print_obj(o, lib, fmt=fmt.format(obj_count))
Example #26
0
        def _miss(lib, opts, args):
            self.config.set_args(opts)
            fmt = self.config['format'].get()
            count = self.config['count'].get()
            total = self.config['total'].get()

            albums = lib.albums(decargs(args))
            if total:
                print(sum([_missing_count(a) for a in albums]))
                return

            # Default format string for count mode.
            if count and not fmt:
                fmt = '$albumartist - $album: $missing'

            for album in albums:
                if count:
                    missing = _missing_count(album)
                    if missing:
                        print_obj(album, lib, fmt=fmt)

                else:
                    for item in _missing(album):
                        print_obj(item, lib, fmt=fmt)
Example #27
0
        def _dup(lib, opts, args):
            self.config.set_args(opts)
            fmt = self.config['format'].get()
            count = self.config['count'].get()
            album = self.config['album'].get()
            full = self.config['full'].get()

            if album:
                items = lib.albums(decargs(args))
            else:
                items = lib.items(decargs(args))

            # Default format string for count mode.
            if count and not fmt:
                if album:
                    fmt = '$albumartist - $album'
                else:
                    fmt = '$albumartist - $album - $title'
                fmt += ': {}'

            for obj_id, obj_count, objs in _duplicates(items, full):
                if obj_id:  # Skip empty IDs.
                    for o in objs:
                        print_obj(o, lib, fmt=fmt.format(obj_count))
Example #28
0
def update_items(lib, query, album, move, pretend):
    """For all the items matched by the query, update the library to
    reflect the item's embedded tags.
    """
    with lib.transaction():
        items, _ = _do_query(lib, query, album)

        # Walk through the items and pick up their changes.
        affected_albums = set()
        for item in items:
            # Item deleted?
            if not os.path.exists(syspath(item.path)):
                ui.print_obj(item, lib)
                ui.print_(ui.colorize('red', u'  deleted'))
                if not pretend:
                    item.remove(True)
                affected_albums.add(item.album_id)
                continue

            # Did the item change since last checked?
            if item.current_mtime() <= item.mtime:
                log.debug(u'skipping %s because mtime is up to date (%i)' %
                        (displayable_path(item.path), item.mtime))
                continue

            # Read new data.
            try:
                item.read()
            except Exception as exc:
                log.error(u'error reading {0}: {1}'.format(
                    displayable_path(item.path), exc))
                continue

            # Special-case album artist when it matches track artist. (Hacky
            # but necessary for preserving album-level metadata for non-
            # autotagged imports.)
            if not item.albumartist:
                old_item = lib.get_item(item.id)
                if old_item.albumartist == old_item.artist == item.artist:
                    item.albumartist = old_item.albumartist
                    item._dirty.discard('albumartist')

            # Check for and display changes.
            changed = ui.show_model_changes(item,
                                            fields=library.ITEM_KEYS_META)

            # Save changes.
            if not pretend:
                if changed:
                    # Move the item if it's in the library.
                    if move and lib.directory in ancestry(item.path):
                        item.move()

                    item.store()
                    affected_albums.add(item.album_id)
                else:
                    # The file's mtime was different, but there were no
                    # changes to the metadata. Store the new mtime,
                    # which is set in the call to read(), so we don't
                    # check this again in the future.
                    item.store()

        # Skip album changes while pretending.
        if pretend:
            return

        # Modify affected albums to reflect changes in their items.
        for album_id in affected_albums:
            if album_id is None:  # Singletons.
                continue
            album = lib.get_album(album_id)
            if not album:  # Empty albums have already been removed.
                log.debug('emptied album %i' % album_id)
                continue
            first_item = album.items().get()

            # Update album structure to reflect an item in it.
            for key in library.ALBUM_KEYS_ITEM:
                album[key] = first_item[key]
            album.store()

            # Move album art (and any inconsistent items).
            if move and lib.directory in ancestry(first_item.path):
                log.debug('moving album %i' % album_id)
                album.move()
Example #29
0
def update_items(lib, query, album, move, color, pretend, config):
    """For all the items matched by the query, update the library to
    reflect the item's embedded tags.
    """
    with lib.transaction():
        items, _ = _do_query(lib, query, album)

        # Walk through the items and pick up their changes.
        affected_albums = set()
        for item in items:
            # Item deleted?
            if not os.path.exists(syspath(item.path)):
                ui.print_obj(item, lib, config)
                if not pretend:
                    lib.remove(item, True)
                affected_albums.add(item.album_id)
                continue

            # Did the item change since last checked?
            if item.current_mtime() <= item.mtime:
                log.debug(u'skipping %s because mtime is up to date (%i)' %
                        (displayable_path(item.path), item.mtime))
                continue

            # Read new data.
            old_data = dict(item.record)
            item.read()

            # Special-case album artist when it matches track artist. (Hacky
            # but necessary for preserving album-level metadata for non-
            # autotagged imports.)
            if not item.albumartist and \
                    old_data['albumartist'] == old_data['artist'] == \
                        item.artist:
                item.albumartist = old_data['albumartist']
                item.dirty['albumartist'] = False

            # Get and save metadata changes.
            changes = {}
            for key in library.ITEM_KEYS_META:
                if item.dirty[key]:
                    changes[key] = old_data[key], getattr(item, key)
            if changes:
                # Something changed.
                ui.print_obj(item, lib, config)
                for key, (oldval, newval) in changes.iteritems():
                    _showdiff(key, oldval, newval, color)

                # If we're just pretending, then don't move or save.
                if pretend:
                    continue

                # Move the item if it's in the library.
                if move and lib.directory in ancestry(item.path):
                    lib.move(item)

                lib.store(item)
                affected_albums.add(item.album_id)
            elif not pretend:
                # The file's mtime was different, but there were no changes
                # to the metadata. Store the new mtime, which is set in the
                # call to read(), so we don't check this again in the
                # future.
                lib.store(item)

        # Skip album changes while pretending.
        if pretend:
            return

        # Modify affected albums to reflect changes in their items.
        for album_id in affected_albums:
            if album_id is None:  # Singletons.
                continue
            album = lib.get_album(album_id)
            if not album: # Empty albums have already been removed.
                log.debug('emptied album %i' % album_id)
                continue
            al_items = list(album.items())

            # Update album structure to reflect an item in it.
            for key in library.ALBUM_KEYS_ITEM:
                setattr(album, key, getattr(al_items[0], key))

            # Move album art (and any inconsistent items).
            if move and lib.directory in ancestry(al_items[0].path):
                log.debug('moving album %i' % album_id)
                album.move()
Example #30
0
def update_items(lib, query, album, move, pretend):
    """For all the items matched by the query, update the library to
    reflect the item's embedded tags.
    """
    with lib.transaction():
        items, _ = _do_query(lib, query, album)

        # Walk through the items and pick up their changes.
        affected_albums = set()
        for item in items:
            # Item deleted?
            if not os.path.exists(syspath(item.path)):
                ui.print_obj(item, lib)
                ui.print_(ui.colorize('red', u'  deleted'))
                if not pretend:
                    item.remove(True)
                affected_albums.add(item.album_id)
                continue

            # Did the item change since last checked?
            if item.current_mtime() <= item.mtime:
                log.debug(u'skipping %s because mtime is up to date (%i)' %
                        (displayable_path(item.path), item.mtime))
                continue

            # Read new data.
            try:
                item.read()
            except Exception as exc:
                log.error(u'error reading {0}: {1}'.format(
                    displayable_path(item.path), exc))
                continue

            # Special-case album artist when it matches track artist. (Hacky
            # but necessary for preserving album-level metadata for non-
            # autotagged imports.)
            if not item.albumartist:
                old_item = lib.get_item(item.id)
                if old_item.albumartist == old_item.artist == item.artist:
                    item.albumartist = old_item.albumartist
                    item._dirty.discard('albumartist')

            # Check for and display changes.
            changed = ui.show_model_changes(item,
                                            fields=library.ITEM_KEYS_META)

            # Save changes.
            if not pretend:
                if changed:
                    # Move the item if it's in the library.
                    if move and lib.directory in ancestry(item.path):
                        item.move()

                    item.store()
                    affected_albums.add(item.album_id)
                else:
                    # The file's mtime was different, but there were no
                    # changes to the metadata. Store the new mtime,
                    # which is set in the call to read(), so we don't
                    # check this again in the future.
                    item.store()

        # Skip album changes while pretending.
        if pretend:
            return

        # Modify affected albums to reflect changes in their items.
        for album_id in affected_albums:
            if album_id is None:  # Singletons.
                continue
            album = lib.get_album(album_id)
            if not album:  # Empty albums have already been removed.
                log.debug('emptied album %i' % album_id)
                continue
            first_item = album.items().get()

            # Update album structure to reflect an item in it.
            for key in library.ALBUM_KEYS_ITEM:
                album[key] = first_item[key]
            album.store()

            # Move album art (and any inconsistent items).
            if move and lib.directory in ancestry(first_item.path):
                log.debug('moving album %i' % album_id)
                album.move()
Example #31
0
def update_items(lib, query, album, move, pretend):
    """For all the items matched by the query, update the library to
    reflect the item's embedded tags.
    """
    with lib.transaction():
        items, _ = _do_query(lib, query, album)

        # Walk through the items and pick up their changes.
        affected_albums = set()
        for item in items:
            # Item deleted?
            if not os.path.exists(syspath(item.path)):
                ui.print_obj(item, lib)
                if not pretend:
                    lib.remove(item, True)
                affected_albums.add(item.album_id)
                continue

            # Did the item change since last checked?
            if item.current_mtime() <= item.mtime:
                log.debug(u'skipping %s because mtime is up to date (%i)' %
                          (displayable_path(item.path), item.mtime))
                continue

            # Read new data.
            old_data = dict(item.record)
            try:
                item.read()
            except Exception as exc:
                log.error(u'error reading {0}: {1}'.format(
                    displayable_path(item.path), exc))
                continue

            # Special-case album artist when it matches track artist. (Hacky
            # but necessary for preserving album-level metadata for non-
            # autotagged imports.)
            if not item.albumartist and \
                    old_data['albumartist'] == old_data['artist'] == \
                        item.artist:
                item.albumartist = old_data['albumartist']
                item.dirty['albumartist'] = False

            # Get and save metadata changes.
            changes = {}
            for key in library.ITEM_KEYS_META:
                if item.dirty[key]:
                    changes[key] = old_data[key], getattr(item, key)
            if changes:
                # Something changed.
                ui.print_obj(item, lib)
                for key, (oldval, newval) in changes.iteritems():
                    _showdiff(key, oldval, newval)

                # If we're just pretending, then don't move or save.
                if pretend:
                    continue

                # Move the item if it's in the library.
                if move and lib.directory in ancestry(item.path):
                    lib.move(item)

                lib.store(item)
                affected_albums.add(item.album_id)
            elif not pretend:
                # The file's mtime was different, but there were no changes
                # to the metadata. Store the new mtime, which is set in the
                # call to read(), so we don't check this again in the
                # future.
                lib.store(item)

        # Skip album changes while pretending.
        if pretend:
            return

        # Modify affected albums to reflect changes in their items.
        for album_id in affected_albums:
            if album_id is None:  # Singletons.
                continue
            album = lib.get_album(album_id)
            if not album:  # Empty albums have already been removed.
                log.debug('emptied album %i' % album_id)
                continue
            al_items = list(album.items())

            # Update album structure to reflect an item in it.
            for key in library.ALBUM_KEYS_ITEM:
                setattr(album, key, getattr(al_items[0], key))

            # Move album art (and any inconsistent items).
            if move and lib.directory in ancestry(al_items[0].path):
                log.debug('moving album %i' % album_id)
                album.move()