beetbox / beets

music library manager and MusicBrainz tagger
http://beets.io/
MIT License
12.77k stars 1.82k forks source link

Add a new `date` field that abstracts over `day`, `month`, and `year` and allows date queries #2872

Open jones1008 opened 6 years ago

jones1008 commented 6 years ago

In some cases it would be useful to use date and date range querys with the year tag.

So a query like: beet list 'added:-5y..' would also be useful with the year tag: beet list 'year:-5y..' This query would list all tracks from the last 5 years. It is more dynamic than those:

beet list 'year:2013..2018'
beet list 'year:2013..'

Any thoughts on that?

sampsyo commented 6 years ago

Interesting! What do you think about a slightly refined proposal: we create a virtual (i.e., computed) field called date that includes the information from the year, month, and day fields that get stored in files' metadata? This field would work the same way as added or mtime and support these queries, but year itself would remain a plain integer.

jones1008 commented 6 years ago

This sounds more solid than my version! Very good!

sampsyo commented 6 years ago

OK, this is a good idea. Thanks for the suggestion.

solson commented 4 years ago

FYI it seems like you can implement this with the following configuration:

plugins: inline types

types:
  date: date

item_fields:
  date: |
    import datetime
    return datetime.datetime(year or 1, month or 1, day or 1).timestamp()

album_fields:
  date: |
    import datetime
    return datetime.datetime(year or 1, month or 1, day or 1).timestamp()

The reason I have all the x or 1 expressions is that many of my tags seem to lack specific dates, and set things like year:1994 month:0 day:0 when only the year is known. I'm not sure what an official implementation of date should do in this case, but it would be nice to figure it out. It's nice that inline makes this possible, but this seems like a case where it should be replaced by a built-in feature.

eternaleye commented 7 months ago

You can also collapse the definition into a one-liner by using __import__ (and some slight changes to work on my Python, due to negative timezones making year 1 become the illegal year 0 internally in datetime):

plugins: inline types

types:
  date: date

item_fields:
  date: __import__("datetime").datetime(max(year, 2), month or 1, day or 1).timestamp()

album_fields:
  date: __import__("datetime").datetime(max(year, 2), month or 1, day or 1).timestamp()

I did this, and the same for the original_ fields.