beetbox / beets

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

Rating metadata tags #2530

Open akovia opened 7 years ago

akovia commented 7 years ago

Not sure what the ratings philosophy is here but I'd love to see a ratings plugin that could help manage them. I've gone though a ton of music player over nearly 20 years and it seems every single one has it's own rating system. A plugin to either unify them into a single preferred tag, or writing multiple tags would be immensely helpful.

Maybe it could read all (plugin supported) existing ratings and you could choose the order of priority to set the new rating to a single tag, or equalize everything by writing a rating to all supported tags.

Highest Rated fmps_rating rating:banshee POPM fmps_rating_amarok_score rating:quodlibet Lowest rated etc..

The option to write a normalized rating to all supported tags would make a library completely portable, or an option to strip all but one preferred tag.

ratings:
    order: highest fmps banshee amarok quodlibet popm lowest
    onetag: fmps # write this tag and clear all other rating tags.
    multitag: * # list of tags to write or * for all supported

Would this be useful to anyone else?

Edit: I realized a while back that my proposed config options were not completely thought out. Wanted to update it to be clearer and more streamlined.

ratings:
    read_precedence: highest fmps banshee amarok quodlibet popm lowest
    write: fmps # write to this tag (or more if supported)
    clear: yes # delete all ratings tags not written to above
sampsyo commented 7 years ago

Interesting idea! I'm guessing that most of the tag formats you've mentioned here are for the "free-form" formats like Vorbis Comments?

For what it's worth, the usual "beets way" of doing things like this would be a simple "read any, write all" policy to maximize compatibility with other tools.

See also #122.

mdorman commented 7 years ago

POPM is in the id3v2 spec. The only other one I am specifically familiar with (rating:banshee) is indeed just a comment field.

I have done a little work on a plugin to manage this stuff, so I can finally ditch Banshee; I stalled out on it for a while, but was intending to work on it a bit this afternoon., in fact.

The strategy I had arrived at was not unlike what was proposed here: to have a beets field, userrating (rating being already taken by the mpdstat plugin) that has "codecs" for the various fields in use in the wild.

The part I hadn't quite thought my way through, but @akovia's proposal lays out pretty simply, is the idea of being able to specify, in order of precedence, what will be read from, and being able to specify what will be written; writing everything seems like it could get unwieldy, just because the casual research I've done suggests that everyone does things differently. :)

akovia commented 7 years ago

I am certainly out of my depth concerning the actual programming of it, but I'm happy to research and test as needed. Just point me in the right direction.

everyone does things differently.

That is a fact! At least not everyone writes directly to the tags, opting for the DB approach instead. From my limited research, POPM and FMPS are probably the 2 most popular formats that actually have specs. Banshee, Clementine, and Amarok all use different tag names, but the scale of 0.1 - 1.0 seem to be the same. I would think this is just a matter of changing tag names where appropriate.

POPM uses an email address that makes things a bit more dodgy. Would be nice if there was an option to specify a preferred email address when/if creating POPM tags, with a default of no@email.

Some links if it makes things easier. Vorbis Comment FMPS POPM Quodlibet

Please let me know if I can be of any help.

sampsyo commented 7 years ago

Cool; thanks for expanding on this, @mdorman and @akovia! I've marked this ticket as a feature request specifically for the ability to read and write the various standards for storing ratings. Once we have that, there are lots of options about how exactly to use them—but we can start by getting basic support for the (pseudo-)standards first.

mdorman commented 7 years ago

@sampsyo What is the policy/preference on including plugins in beets proper? What progress I've made so far has actually been in a separate repo as an external plugin; I'll continue that at least until I feel like it's in a releasable state, just for ease of development, but is this something you would like to see included?

sampsyo commented 7 years ago

Good question. We don't have written guidelines (although that would be a good idea!). Instead, the general standard is that we (where "we" is the beets hivemind) promise to support and maintain all the plugins that we bring into core distribution. That means, basically, that it needs to be relevant enough to users and also meet a certain code quality standard (including docs and tests) so we have a reasonable chance of doing right by the plugin in the future.

Anyway, depending on the scope, I can see this being a good match for inclusion! Is this the repo I should be watching?

mdorman commented 7 years ago

@sampsyo yeah that's the repo. I know it's pretty bare at the moment. :) I tend to be a bit of a "do a lot of rebasing in the local git repo" sort of person.

reconmaster commented 7 years ago

I would definitely be interested in this. I've had a lot of success with beets so far, but I'm hesitant to use it on my exisitng library as I manually cook the ratings in the comment as rathing=1,2,3,4,5. I've used diferent player rating systems, but after a variety of these landed in the abandonware pile.

On a number of occasions this has led to me losing a large amount of rating efforts (especially for a few players that wouldn't touch metadata which was an oversight on my part for failing to notice until too late). So far the best method I have is to use my comment to then modify in whatever player I am trying to use.

I also use the scrub plugin, so I am a little concerned about launching beets on my music database until some sort of official rating metadata is supported. I have no problem abonding my current rating= method provided I have a robust way to migrate that into beets.

I've spent years curating ratings as they help me refine the collection for different playlist/dj purposes. So having something that would support rating metadata would seal the deal on beets. Nice work so far!

P.S. I just realized the types plugin may be the solution for this. I need to experiment to see if it will automatically deterimine the rating= comment in my files or if scrub will take wipe it out.

mdorman commented 7 years ago

After an unfortunately long time, I have actually resumed working on this. I've pushed up my extraordinarily stupid proof of concept to an appropriate branch

So, I now have a dumb-as-dirt plugin that can (only!) read a banshee rating from a .flac file, and store that in a userrating custom field that I have defined as a two-digit INTEGER (0-99 seems like a reasonable range to me).

To start to generalize it, it is my perception that I'm going to need to write some number of StorageStyle instances that would, for instance, handle the conversion from whatever scale the original tag uses (for instance, RATING:BANSHEE is actually stored as a float ranging from 0 to 1) to the internal scale I've chosen, and vice versa. Is that enough?

@sampsyo I would appreciate any guidance you might have.

sampsyo commented 7 years ago

Hi, @mdorman! This plugin looks great already. Nice work. Indeed, writing a series of StorageStyles to capture the various tag formats (and their numerical scales) is exactly what’s needed here.

Bonus points, of course, if it’s possible to point to documentation or example files that justify the way each StorageStyle works…

mdorman commented 7 years ago

@sampsyo Good point about including documentation for future archaeologists. :)

For what it's worth, I figure I'll handle the cases for which I have personal examples (basically, flac/banshee and mp3), or can easily locate documentation (ogg, I suppose, maybe other things), and then try and make it as easy and obvious as possible for additional contributors to include more stuff. No need to add the kitchen sink before declaring success. Does that make sense to you?

Finally, I do wonder if you have any suggestions about testing; I know basically nothing about testing in Python (for that matter, I can't really claim to know Python, but I can mostly fake that). I'm currently doing some testing using a .flac file from my collection and initializing a new library and importing it and doing a quick search in a shell script. That is adequate for this stage of development, but it's clearly not a long-term solution. Ideas?

sampsyo commented 7 years ago

Absolutely. Starting with the popular options sounds great, and we can expand the set on demand as people make requests.

You're doing a great job of faking Python expertise! We actually have a fairly elaborate suite of tests in our test/ directory. Some are more readable than others, but by scanning around, you might find a smallish file that could serve as an example. We also have a useful wiki page that describes how to run the tests: https://github.com/beetbox/beets/wiki/Testing

mdorman commented 7 years ago

@sampsyo (and anyone else) So, on the one hand, I made some good progress on the StorageStyle front (code is in the aforementioned branch)...and then promptly ran into some design questions that I'd like some feedback on.

So I started off thinking I'd do a 1:1 rating-style-to-storage-style. I made it to StorageStyle #2 before I started to think that was a bad idea. :smile:

So my current thinking is that I'll go with something more analogous to how others are done: roughly a StorageStyle per format, and build the smarts into the get() method to sort through the options. I imagine eventually making this process somewhat configurable. Do you see any downsides to this?

Also, this leads me to my second design decision: I'm starting to think we should strongly normalize what we write---that is, while we want to read as much stuff as people will contribute, we should always write one-tag-per-format, or as close as we can get to that.

I guess I'm less certain that this is the right thing to do, but I worry that the alternatives make things a lot more complex almost immediately: at the very least we have to provide people with a way to say what they want written if a value isn't already present, and that configuration needs to conceivably handle different options for different formats, and then should that always be normalizing, or should it only be a fallback if there wasn't a value already there, etc., etc.

Any thoughts? I'm not unwilling to make things more sophisticated over time, but I'm a big believer in Minimum Viable Product, too.

sampsyo commented 7 years ago

Good points all! Here's my recommendation for now: let's start with the simplest possible thing, release it, and go from there. Specifically, this is what that would look like:

Does that sound reasonable?

mdorman commented 6 years ago

@sampsyo I'll give it a shot; I have some slight misgivings, but it probably just won't be clear what the right answer is until it's gotten more exposure.

mdorman commented 6 years ago

@sampsyo So, I've got something that is still a little too simplistic (it hard-codes all scaling for non-mp3 tags, which is too restrictive), but I believe more or less does what you suggest. I will admit to a little bit of potential confusion, though.

Specifically, if you look at the last commit of my POC branch---which is what sets the import_stages and so forth---it appears superfluous; without it the userrating field still gets set and with it I get messages saying that the existing value won't be overwritten.

So am I right in inferring that by adding a media field, at least the import process should "just work"? Is the only need for a command here for setting stuff by hand?

Thanks for clearing up any confusion (and any other pointers you might have)!

sampsyo commented 6 years ago

Yes! You've got that right—the existing infrastructure in beets should take care of transferring the in-database values for a field to corresponding MediaField values. Your extra import stage, while well-intentioned, should probably not be necessary.

mdorman commented 6 years ago

Right---I was copying code from other plugins, but I don't know that any of them were actually adding new media fields, so the stuff I copied was'n't actually pertinent.

OK, with that cleared up, I need to cogitate a little bit on how to make the non-MP3 case straightfoward to extend (since in that case there may well be a conversion required).

Err, I suppose I should have a command to allow people to search & set the value. Do you have any suggestions for models to look at for that?

sampsyo commented 6 years ago

Hmm... it seems like you can again get by without too much specific effort. The list and modify commands let users query and set any field, so it should hopefully work the same for a new rating field. It would be useful to think about how queries and modification should ideally work in that context

Then, the way to go about implementing those is with our field type system. A good example might be the musical key type, which is in library.py.

akovia commented 6 years ago

Just wanted to ping to see if there is still any interest in this. I truly believe this is still a huge feature that isn't being exploited by anyone. The ability to make your music collection player agnostic is seriously needed.

jphautin commented 5 years ago

just a message posted here if someone is interested in rating in beets. I am taking back the effort to be able to import rating of other players. For now, I am focusing on mp3 but will try to also add flac and then wma support If I can. plugin can be tested from repository https://github.com/jphautin/beets-userrating/

kifty commented 4 years ago

I know it's been a year, but I'm very interested! I tried installing your plugin, but I'm getting a "init.py does not call declare_namespace()" error. Similar to @reconmaster above, I use a simple %rating%=1,2,3,4,5 in foobar2000 and I'd love to to map from my tags to flexible attributes in Beets. I assume they're TXXX frames for MP3 and Vorbis keys for FLAC.

I was trying to dig through the documentation to do it myself, but then I ran into this issue. Any chance it would for my use case?

xhocquet commented 9 months ago

Wanted to +1 this feature request and point out a use-case I'm running into -

I have existing mp3s in my library with thousands of tracks rated 5 stars for auto-playlists. Those ratings are ID3v2 tags on the files. I'm going through and replacing them with FLAC versions when I can find them. I want to keep my track ratings. Today I have to go album-by-album, remember the ratings, and re-apply them to the files after I've imported them and replaced my lower quality versions. If beets would track at least the standard rating field, I could create a workflow whereby the ratings are part of the beets DB and reapplied to the newly imported versions of the songs.