beets: Path config query does not work with album-level flexible attributes

Problem

Path queries do not work with attributes that are set at album level. More specifically, I import an album setting at the same time a flexible attribute. I have various paths that are supposed to be modified by this attribute. Though the attribute is set at import time, the query at the path will not match, neither at import time, nor at a later time.

My configuration:


item_fields:
    initial: (albumartist_sort or artist_sort or albumartist or artist or '_')[0].upper()
    disc_count:  u'%02i.' % (disc)
    disc_and_track: u'%02i.%02i' % (disc, track) if
                    disctotal > 1 else u'%02i' % (track)
    definite_year: u'%04i' % original_year or original_date[:3] or year or date[:3] or 0

album_fields:
    cond_release_category: |
            if albumstatus.lower()=='official':
                    if albumtype.lower() in ['album', 'compilation', 'ep']:
                            return None
                    elif supergenre=='Soundtrack' and albumtype.lower() in ['soundtrack']:
                            return None
                    else:
                            return albumtype.capitalize()
            else:
                    return albumstatus.capitalize()
    boxset_folder: |
            if boxset==1:
                    boxdisc_folder=u'%i. %s' % disc, disctitle
                    if boxdisc_year: boxdisc_folder=u'%s %s' % boxdisc_folder, boxdisc_year
                    return boxdisc_folder
            else:
                    return None

paths:
    default: $supergenre/%asciify{$initial}/$albumartist/%if{$cond_release_category,$cond_release_category/}[$definite_year] $album%aunique{albumartist album,albumdisambig label catalognum year}/$disc_and_track - $title
    boxset:1: $supergenre/%asciify{$initial}/$albumartist/%if{$cond_release_category,$cond_release_category/}[$definite_year] $album%aunique{albumartist album,albumdisambig label catalognum year}/$disc_count $disctitle%ifdef{boxdisc_year, ($boxdisc_year)}/$track - $title
    singleton: Non-Album/$artist - $title
    comp: $supergenre/Compilations/$album%aunique{}/$disc_and_track - $title
    supergenre:Soundtrack: Soundtrack/$album/%if{$disctotal>1,$disc.}$track $title

And this is the result:

user@beethost:~$ beet ls -a supergenre:Soundtrack
...
Michael Nyman - The Piano
...
user@beethost:~$ ls -l /music/Soundtrack/N/Michael\ Nyman/
total 0
drwxrwxr-x 2 user user 0 Jan 26 08:50 [1993] The Piano```

Note that the path follows the default template and that the album attribute expands correctly in the template.

### Setup
beets version 1.4.6
Python version 2.7.13

Relevant thread at discussion board:
https://discourse.beets.io/t/path-config-and-album-level-flexible-ttributes-at-import-time/278/3

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 3
  • Comments: 15 (8 by maintainers)

Commits related to this issue

Most upvoted comments

I want this to move music to specific sub-folders based on a flexible attribute that is set at time of import. My workaround is to use the inline plugin like so:

plugins: inline
paths:
  default: lib/$collection/$albumartist/$album%aunique{}/$track $title
  singleton: lib/$collection/non-albums/$artist/$title
  comp: lib/$collection/compilations/$album%aunique{}/$track $title
album_fields:
  collection: |
    try:
      return coll
    except NameError:
      return ''
item_fields:
  collection: |
    try:
      return coll
    except NameError:
      return ''

This is for a flexible attribute named coll, importing with beet import --set coll=hello .. This isn’t really one-size fits all, but it works for me. If you only add the album_fields section and not item_fields you’ll have working imports but $collection will be undefined when you attempt to do beet mv for example.

It is already implemented, just not merged yet. We’re still looking for testers. See #2988 for more.

I should probably rebase the branch to current master.

Wow; that’s awesome! Thanks for digging in and working that out so quickly.

I agree, first of all, that those are the operative questions. It does seem important to be able to explicitly opt into the opposite behavior. My first hunch, however, says that the “cascade” from album to item should be the default—since that’s the way that album-level attributes normally “feel” during formatting and other operations. It might be a good idea for the ipfs plugin to move to two separate field names, for example—an album-level one and an item-level one.

This would mean that querying the item-level attributes alone would be an “advanced” feature, only to be needed in special circumstances—ordinarily, when something has gone wrong and items are somehow out of sync with albums. We could invent some funky query syntax to specify when to use that advanced behavior.

How does that sound to everybody?

So, I looked into this a little and tried adding a fallback to Item.__getitem__ which would also check the album’s flexattrs in case the key couldn’t be found, but that hasn’t been successful so far. Tracking down the code for query generation, I determined this to be the most likely place to add it (via FieldQuery.match).

However, what I’m confused about now is how test_library.ItemFormattedMappingTest.test_album_flex_field doesn’t fail. It sets a flexattr on the album but that is then reflected in the item’s formatted mapping, which doesn’t do any lookup on the album itself. Could anyone explain this to me?

https://github.com/beetbox/beets/blob/9577a511cb055f143deb2ad8f2b801595b5f5c3f/test/test_library.py#L520-L524

Edit: Okay, nvm. I missed that the item’s _formatter is FormattedItemMapping.