Picard-Last.fm.ng-Plugin icon indicating copy to clipboard operation
Picard-Last.fm.ng-Plugin copied to clipboard

Prepend and overflow scaling factors

Open skelliam opened this issue 8 years ago • 2 comments

So here's my issue. I love the idea of multiple genres but plain and simple, a lot of the OEM car head units don't support them; they typically will support only one genre. So MusicBrainz Picard doesn't support tagging with genre, and this script does, so I can still get some use from it.

I need exactly ONE genre to be selected and I want it to be a good one. My problem is that if I configure this script to use 1 grouping and 1 genre, the item from grouping would get consumed; then I would get the 'sub genre' which in some instances is just not appropriate.

However the sub genres that come from last.fm are still useful and more detailed than what is chosen for the grouping. So this patch does the following:

It will allow the user to apply a scaling factor on both the OVERFLOWED values from a category AND the PREPENDED values from a category. An example of this in practice:

I: 19:57:08 Last.fm.ng - >>> process track tags
I: 19:57:08 Last.fm.ng - grouping: 10 tag(s) before threshold filter:
I: 19:57:08 Last.fm.ng - grouping: classic rock (1000), rock (450), rock & roll (212), pop (140), hard rock (82), ...
I: 19:57:08 Last.fm.ng - grouping: score threshold: 500.0 (50%)
I: 19:57:08 Last.fm.ng - grouping: 1 tag(s) filtered:
I: 19:57:08 Last.fm.ng - grouping: classic rock (1000)
I: 19:57:08 Last.fm.ng - Final tags before making choice:
I: 19:57:08 Last.fm.ng - classic rock (1000.0)
I: 19:57:08 Last.fm.ng - grouping: metatag: grouping
I: 19:57:08 Last.fm.ng - grouping = Classic Rock
I: 19:57:08 Last.fm.ng - genre: 8 tag(s) before threshold filter:
I: 19:57:08 Last.fm.ng - genre: hard rock (82), honky tonk (72), soft rock (52), blues rock (6), southern rock (6), ...
I: 19:57:08 Last.fm.ng - genre: score threshold: 32.8 (40%)
I: 19:57:08 Last.fm.ng - genre: 3 tag(s) filtered:
I: 19:57:08 Last.fm.ng - genre: hard rock (82), honky tonk (72), soft rock (52)
I: 19:57:08 Last.fm.ng - genre: prepending (and scale by 0.17) from grouping: classic rock (170.0)
I: 19:57:08 Last.fm.ng - Final tags before making choice:
I: 19:57:08 Last.fm.ng - classic rock (170.0),hard rock (82.0)
I: 19:57:08 Last.fm.ng - genre: metatag: genre
I: 19:57:08 Last.fm.ng - genre = Classic Rock

Note that classic rock was chosen for the grouping with a score of 1000. Now, if that value were consumed, the top choice from the 'sub' genres would be hard rock. No way would I classify ANYTHING from Bob Seger as hard rock! So in this case I want to carry over the classic rock tag to the sub genres from last.fm, but I don't want it to ALWAYS win. I want instead to put it in the lineup like the other tags.

So here I multiply both the overflow AND the prepended values from grouping by 0.17 before I insert them into the genre list for consideration. And you can see here that classic rock won the battle instead of hard rock.

Also, there was a bug on line 118 of plugin.py that is fixed here: ', '.join(['{} ({})'.format(t, s) for t, s in overflow]) or 'None' should read: ', '.join(['{} ({})'.format(t, s) for t, s in result[category.prepend]]) or 'None'

My config.ini reads like so:

[global]
lastfm_key = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

[category-defaults]
; used to join tags if >1 are to be used (None to use multtag)
separator = ", "

[category-grouping]
# grouping is used as major/high level category
limit = 1
enabled = True
threshold = 0.5
overflow = genre
overflow_scale = 0.17
metatag_album = albumgenre
metatag_track = grouping 

[category-genre]
limit = 1
threshold = 0.4
prepend = grouping
prepend_scale = 0.17
metatag_album = albummood
metatag_track = genre

And I'm getting pretty good results from this.

skelliam avatar Jul 24 '16 00:07 skelliam

thanks! that sound pretty useful.

i am a little reluctant to merge right away, if this changes behavior for people "blindy" updating the plugin. i admit i haven't looked though all the math, but it does change behavior, even with scale factors 1, because overflowed tags are re-sorted by score, right?

fdemmer avatar Jul 24 '16 03:07 fdemmer

Yes you're right Florian, the overflowed tags are re-sorted. A side-effect of this also, is that I call your existing sort function, which will sum existing tags. So if you overflow rock(100) and the genre list has rock(50) you will get rock(150) in the final list. I thought of writing a separate sort function without grouping/summing scores but I wasn't sure that I wanted to not sum the results...

No offense taken if you don't merge it!! :-) But it is there if someone wants to pull it, especially if you want better genres for music on a USB stick.

Multiple genres seems to be a grey area in the ID3 spec. Both my Jeep and my Ford have USB playback capability, and both grabbed the entire semi-colon separated string and used it. (I used semicolons after I read this).

Probably need to create some unit tests to confirm that the functionality isn't broken with this addition even with scaling of 1.0, I agree.

There was one bugfix in there that you might want to grab, I think I pointed it out in the comments. The log would always report 'None' for overflow -- I think I highlighted the correct lines in my comments.

I think this could still be improved. For example, the scaling could be smarter. I've seen some examples where the grouping tags are like:

rock(10000), hard rock(4000), heavy metal(1000) and then the genres: classic rock(400), blah(175), blah(50), etc.

In this case a fixed scaling of whatever (in my case 0.17) would prepend rock (1700) to the genres. This is going to win no matter what. So somehow normalizing both lists might be interesting.

Also I want to say, I thought I was pretty decent at Python but after looking over your very clean OO implementation here I learned a lot. Nicely done.

skelliam avatar Jul 24 '16 13:07 skelliam