Different path formatting for FLAC and MP3|AAC with %if and inline plugin

This question was buried in another thread so I wanted to post is as a single request hoping for a suggestion.

I want part of my Path to be different for MP3 and FLAC albums.
MP3 albums should have ($format $albumbitrate) in the path and
FLAC albums ($format $bitdepth-$samplerate)

The album format is determined by the following code via the inline plugin

# Inline plugin template
album_fields:  
  format: |
       formatList = []
       for item in items:
           formatList.append(item.format)
       return formatList

I’ve tried the following in my path (and many many other formattings) but didn’t get it to work.

%if{$format:"FLAC",($format $bitdepth-$samplerate),($format $bitrate)}

I probably miss something in what I can put in the various %if statement fields.
As you can see my reasoning was that if my conditional is something like “%if(format is FLAC then print information for FLAC otherwise print information for MP3 and AAC”. But to no avail.

Thanks for any suggestions,
Jan

Ps: @adrian by the way… I’ve succeeded in creating different paths via the format:FLAC before the path like you suggested, but ran in to trouble when trying to achieve the same differentiation for FLAC and MP3 compilations. Didn’t find a way to combine format:FLAC with comp:
It would also have given me many paths to manage. Putting an %if in one path to server FLAC and MP3 would be less administration.

Hello! The %if{} function does not support any manner of complicated expressions like $format:"FLAC"; it really can only tell the difference between empty and nonempty strings (or zero/nonzero numbers).

Using the conditional path formats is the way, as you alluded to:

I’ve succeeded in creating different paths via the format:FLAC before the path like you suggested, but ran in to trouble when trying to achieve the same differentiation for FLAC and MP3 compilations. Didn’t find a way to combine format:FLAC with comp:
It would also have given me many paths to manage. Putting an %if in one path to server FLAC and MP3 would be less administration.

You can combine the compilation matching with the format matching using something like comp:true format:flac as the condition for the path. You’re right, of course, that this will yield lots of different path formats you’ll need to craft separately.

So one other alternative would be to define an inline field called, say, is_flac, that produces 1 or 0 depending on the format. That field would then work with %if{}. This is the same sprit as the %if{$multidisc,...} setup from the FAQ.

Hi, ah yes, of course you can combine information, you can do that in the terminal too, didn’t think of that.
And thanks for clarifying how it would work with the inline plugin. I think that I get the point now.

Wanted to report back after all the help I got from @adrian and @macleodmike to share the results for future forum visitors if they are looking for a similar solution.

My quest was to get an album folder name that contained disambiguation data and specific data for FLAC and MP3/AAC. Beets needed to parse different format related fields for each of them.
You might ask why you would want this info in your folder name (it could be consided as clutter) but I find it very useful to be visually able to determine which albums could use an upgrade from e.g. mp3 --> FLAC or from FLAC 16-44 to 24-96.

For FLAC I wanted to parse
(FLAC bitdepth-samplerate(without kHz))
and for MP3
(MP3 average bitrate(without kbps))

This would result in album names like:

Graceland (1986) (25th anniversary edition 2012) (FLAC 16-44)

and

Stranger to Stranger (2016) (deluxe edition 2016) (MP3 320)

I created (with help) the following inline plugin code with specific variables for

  • a rounded samplerate for use with FLAC
  • a rounded average bitrate for use with MP3/AAC
  • a ‘is_flac’ check to determine if format FLAC is true or false
  • a ‘format’ variable to determine the albums file format.

My inline plugin code looks like this:

  Inline plugin template
  item_fields:
    my_samplerate: round(samplerate / 1000)
    is_flac: 1 if format == "FLAC" else 0
    multidisc: 1 if disctotal > 1 else 0
  album_fields:  
    format: |
         formatList = []
         for item in items:
             formatList.append(item.format)
         return formatList
    av_bitrate: |
         total = 0
         for item in items:
             total += item.bitrate
         return round(total / len(items) / 1000)

This is my full path:

paths:
  default: 'Albums/%the{$albumartist}/$album (%if{$original_year,$original_year}) %aunique{albumartist album year, albumtype label catalognum albumdisambig}%if{$albumdisambig,($albumdisambig $year) }%if{$is_flac,($format $bitdepth-$my_samplerate),($format $av_bitrate)}/%if{$multidisc,$disc-}$track - $title'

And in my path you can see the following %if statement to achieve the differentiation for FLAC and MP3/AAC

%if{$is_flac,($format $bitdepth-$my_samplerate),($format $av_bitrate)}

I hope this helps. If you need clarification please post and I’ll try to clarify.

Thanks again for all the help,
Jan

2 Likes

Thanks for the update, @janpeeters. Did you find a solution to duplicate checking that you’re happy with?

No helas, I didn’t succeed in achieving that.
@adrian suggested to use the samplerate as disambiguation but I added that to my path but didn’t get it to work.

So in the end I asked myself why keep mp3’s when I have a higher resolution FLAC file? I decided that for duplicates the highest quality format stays and the rest gets omitted.

For on the road I have Spotify so I don’t really needed to keep MP3s too.

Thanks for leaving what you got working for you @janpeeters. For my bitrate I was getting values like
(FLAC 24-96.0)

I changed the last line of your av_bitrate to this:
return str(int(total / len(items) / 1000))

…and your my_samplerate to this:
my_samplerate: str(int(samplerate / 1000))

This now gives me my desired (FLAC 24-96) and (MP3 320).

Thanks for your help!

1 Like

Your most welcome!
Great that you got this working too. I’m not sure why my numbers got rounded and yours didn’t. But glad to see that your inline plugin line got you the desired result.

Probably python version difference… / is rounded/floored in python 2, but not in python 3 (whereas // does), unless the python module imports ‘division’ from future, which makes 2 act like 3 in this way. The inline plugin does do that, but maybe it doesn’t apply to the code it compiles and eval’s? Uncertain.

New to all this but I’m trying to achieve close to the same thing. I don’t really care about the mp3 part but would like 24-96 and 16-44, etc. in my path. I think I have the same problem as the two of you when albums contain varying samplerate they end up in different folders.

When I try both of your solution I always get directories with “$my_samplerate” rather than the calculation. Any ideas why? Any and all help greatly appreciated

Hi @47West63rd, could it be that you’re missing something in the inline section of your config file?
I realise that I didn’t post the full section here. I’m not sure that you’ll need all of this, but you can derive from the inline code which parts you need to calculate the information needed for your path. If this doesn’t work, I wouldn’t really know.

Hope this helps!

# Inline plugin template
item_fields:
  multidisc: 1 if disctotal > 1 else 0
  my_samplerate: round(samplerate / 1000)
  is_flac: 1 if format == "FLAC" else 0
album_fields:  
  format: |
       formatList = []
       for item in items:
           formatList.append(item.format)
       return formatList
  av_bitrate: |
       total = 0
       for item in items:
           total += item.bitrate
       return round(total / len(items) / 1000)
  album_bitdepth:  |
       total = 0
       for item in items:
           total += item.bitdepth
       return round(total / len(items))
  album_samplerate:  |
       total = 0
       for item in items:
           total += item.samplerate
       return round(total / len(items) / 1000)
  is_1644: |
       bd = 0
       sr = 0
       br = 0
       for item in items:
           bd += item.bitdepth
           sr += item.samplerate
           br += item.bitrate
       bd = round(bd / len(items))
       sr = round(sr / len(items) / 1000)
       br = round(br / len(items) / 1000)
       return 1 if bd == 16 and sr == 44 and br > 320 else 0

Thanks for the quick reply. Still no luck. In your longer code above I noticed “album_samplerate”. That got me to thinking that what I’m after is the the album level directory creation with (24-96) so I probably don’t want my_samplerate. So I changed it and now I get directories like this:
(FLAC 16-$album_samplerate)

Being new at all this I’m still unclear how the item_fields and album_fields work

Can you please show me your working default path? I think the copy paste I did above from your 2019 post may have changed on your end as you worked this all out. This is what I’m currently using:

default: 'Albums/%the{$albumartist}/$album (%if{$original_year,$original_year}) %aunique{albumartist album year, albumtype label catalognum albumdisambig}%if{$albumdisambig,($albumdisambig $year) }%if{$is_flac,($format $bitdepth-$album_samplerate),($format $av_bitrate)}/%if{$multidisc,$disc-}$track - $title'

but have similar result with my_samplerate

My current path is this:

paths:
  default: 'Albums/%the{$albumartist}/%if{$original_year,$original_year} - $album %aunique{albumartist album year, albumdisambig}%if{$albumdisambig,($albumdisambig $year) }%if{$is_1644,,%if{$is_flac,($format $album_bitdepth-$album_samplerate),($format $av_bitrate)}}/%if{$multidisc,$disc-}$track - $title'

I realize that I also had to add something else to my config to get it to work. I tend to remember that I needed to add the section below because otherwise beet would treat the inline data as strings instead of integers. But it might be obsolete.
I’ve put it under the paths section.
Try and see if this solves it.
And otherwise check your path again and see if your brackets { } are pairs/closed.

types:
    av_bitrate: int
    my_samplerate: int
    bitdepth: int
    album_bitdepth: int
    album_samplerate: int
    rating: int
1 Like

Many thanks again. Total rookie mistake. I did not have “inline” in my plugins. Soooo much wasted time.

:upside_down_face: no problem, happy you found the problem.

I always appreciate the generosity of music people. Hoping this helps someone in the future. I want the max sample rate for the album so it can be applied to the directory name. What @janpeeters has provided is the average. I’m sure he knows that and has good reasons. If by chance you are trying to do what I was you can modify his code slightly to this:

album_samplerate:  |
       maxsamplerate = 0
       for item in items:
            if item.samplerate > maxsamplerate:
                 maxsamplerate = item.samplerate
       return round(maxsamplerate / 1000)
       #total = 0
       #for item in items:
       #    total += item.samplerate
       #return round(total / len(items) / 1000)
       #return str(int(total / len(items) / 1000))

original code is handy and I’m not a python programmer so leaving it around for reference later.

Thanks again!!!

1 Like

@47West63rd Thanks for sharing this. I did indeed know that my workaround calculates the average, but I don’t have the Python skills to write something that would do what you created.
I’ve tried it and it works well.

With a specific album also the bitdepth was different throgh the various tracks, so the result was a (FLAC 17-45).
Do you know how to adapt your code to also calculate a rounded bitdepth to 16 or 24?

I’m a software developer by profession, just never used Python. I’m sure I can figure it out. Can you tell me a bit more detail about what you are trying to do? Maybe an example of the problem and what you want the solution to be? Sounds like maybe rounding up or rounding down is not giving you the answer you want???

This should work (I also condensed the for loop into a generator expression):

album_samplerate: |
  return round(max(item.samplerate for item in items) / 8000) * 8

This rounds the value to the nearest multiple of 8, so for example 17000 becomes 16.

1 Like

Thanks a lot for this code @jackwilsdon.
I guess though, that samplerate should be replaced by bitdepth in your code?
I tried the adaptation below, but get a 0 as a result.

I was also wondering if this wouldn’t give an inaccurate impression of the overall quality of the files. The highest bitdepth is being used I think while sometimes (when e.g. one file has 24 and all others have 16 it gives the lowest would be more accurate. I guess the same counts for @47West63rd solution?

album_bitdepth: |
  return round(max(item.bitdepth for item in items) / 8000) * 8