2 Actions: Append term to Genre unless term already exists and distribute terms to fields if not duplicated

Hello and Happy New Year!!
I have a system where I have custom fields for multiple genres to attach to a song. So I have the regular %genre% along with %genre1%, %genre2%, %genre3% and so on.

When I am done tagging I just append all these terms to the %genre% field using "/" as the delimiter. In order to do this, I have created this tag to tag action with the field %genre% formatted by the following string:

%genre%$if(%genre1%, / %genre1%,)$if(%genre2%, / %genre2%,)$if(%genre3%, / %genre3%,)$if(%genre4%, / %genre4%,)$if(%genre5%, / %genre5%,)$if(%genre6%, / %genre6%,)$if(%genre7%, / %genre7%,)$if(%genre8%, / %genre8%,)$if(%genre9%, / %genre9%,)$if(%genre10%, / %genre10%,)

It works well but sometimes there are duplicate terms. I am trying to figure out how to modify the string to tell MP3Tag to not include the term if it is previously found in any of the other fields.

For example if %genre% is "Christmas / Blues / Subdued" and %genre1% is "Christmas" then the term "Christmas" would not be appended to %genre%.

Similarly if %genre1% is "Jazz% and %genre3% is "Jazz", then only one instance of "Jazz" would be appended to %genre%. Where the result for %genre% would be "Christmas / Blues / Subdued / Jazz"

I am also wondering if I could modify the guess values action to reverse distribute the terms found in %genre% to the %genre1% %genre1% %genre3% fields, and so on, but only if they are not duplicated. Where the Source format would be %genre% and the guessing pattern would be %genre1% / %genre2% / %genre3% / %genre4% and so on.

I am just not sure how to instruct MP3Tag to skip a term if it is a duplicate.

1 Like

If you insist doing it inside mp3tag, it could be possible along the line of doing repeated genre comparison. Could be something like this:

  1. Copy genres to temporary tags, let's say %TEMP1% to %TEMP10%
  2. Comparison starting from the last pair and work backward: format %TEMP10% to
  1. By this way, you eliminate the last tag if it's identical to previous one, and keep it if different.
  2. Repeat this process for 45 times (9*10/2)
  3. There is a shorthand for joining the result, you can set %genre% to
%TEMP1%[ / %TEMP2%][ / %TEMP3%]...

Note that it is very clumsy and the complexity grows exponentially if you increase possible genre count. Personally I would rather search or write external tool instead.

Thank you for your suggestion. I will try to digest it and report back. I started to consider that comparing it to %genre% is not really necessary because it is being created by %genre1%, %genre2%, %genre3% and so on.

So the string just has to compare the contents of each genre other than %genre% and not append the term to %genre% unless it is different from the previous terms.

$if(%genre1%,%genre1%,)$if(%genre2%, / %genre2%,)$if(%genre3%, / %genre3%,)$if(%genre4%, / %genre4%,)$if(%genre5%, / %genre5%,)$if(%genre6%, / %genre6%,)$if(%genre7%, / %genre7%,)$if(%genre8%, / %genre8%,)$if(%genre9%, / %genre9%,)$if(%genre10%, / %genre10%,)

For my second task, I have tried to use guess values with no success.
In Genre I have the following value: "Classic Rock / Hard Rock / Live / Live / GB / eng"
I thought that if I created a guess value with %genre% being the Source Format and the guessing pattern being "%genre1% / %genre2% / %genre3%"
That MP3Tag would populate Classic Rock to GENRE1, Hard Rock to GENRE2, Live to GENRE3 but it does not work.
If I change the guessing pattern to "%genre% / %genre2%"
Then I get Classic Rock to GENRE and Hard Rock / Live / Live / GB / eng to Genre2, so I believe I am close but yet have no cigar.

I don't know why the first term has to be %genre% but it does not work unless it is. I also realized that if I only had 5 genres but the action defines 10 genres, it does not work, so the Action requires some component that "sees" how many genres there are, maybe a $if function? The solution is falling further from my reach. :frowning:

Yes, it is impossible to use Guess Value in one go, given the way it works (shortest possible match). However,

I believe it's totally unrelated to %genre% tag, but depends on number of fragments.

BTW, what you want to achieve can be done iteratively, if you don't mind the repetitiveness.

  1. Copy the genre list into a temp tag, say %TEMP% but with some caveat: you need to append " / " (space slash space) to the end of temp tag. Anyway it should be the same separator you used everywhere.
  2. Guess Values:
    Format: %TEMP%
    Pattern: %genre1% / %TEMP%
  3. Repeat the guess value as many times as necessary, chopping the temp genre list one by one into genre fragments until done.
  4. If you don't append the final separator, the last guess action will fail, and you won't be able to write the final genre.

Thanks again for your help! I see what you are doing here but I wonder why I would need to copy the values to %temp%?
Would it not work with
Format: %genre%
Pattern: %genre1% / %genre%
I am not sure what copying the values to %temp% accomplishes.

For safety. You won't lose any data in case anything has gone wrong.

The guessing pattern has to match the source string exactly in that respect that the guessing pattern must not contain more target fields than the source offers.

For the other list:
Here is a thread that deals with the removal of duplicate string parts from a list of words in a string:

Perhaps you could use that to get rid of duplicates and save yourself a number of $if().

Then, instead of the manually numbered genre fields, it may be an idea to create several fields of the type genre which then could be merged and separated with actions that do not need constant maintainance. Have a look at the $meta() and $meta_sep() function as well as the actions to merge and split fields.

OK, sounds like a good plan, if maybe unnecessary, but I guess it is better to be safer than sorry.

I have solved the first issue using this Action:
Format Value:
Field: Genre
Format String: $trim($regexp(%Genre%,'(?:(?<=/)|(?<=\A))\s*([^/])\s/(?=.?(?<=/)\s\1(?=/|\Z))',,1))

This will get rid of the duplicates in Genre.
I got it from here Merge duplicate words - #10 by dano

I really hope I can figure out how to propagate the specific genres from the Genre field (My second question) as I stupidly erased them after consolidating them in the main Genre field. I will play with abelcheung's suggestion and see if I can get something working.

Have you found out whether your player can cope with multiple entries in GENRE?
Or does it react to a single string separated with special separators, like comma, semicolon or slash?
Can your player cope with user-defined fields and does it then group these together to just 1 genre?
The answers to these questions would then determine the way to go about.

I use the genre field to create smart playlists. Genre contains: X. iTunes has no problems using them. I also know I can change the delimiter to // (or is it '\\') so they are read by foobar as separate genres, but for now I am sticking to iTunes.

Does iTunes read fields like

? Not AFAIK.
So I would think that you address only the actual GENRE field with iTunes and all the other data is lost/ignored.
So I would assume that a comma-separated list in GENRE would be read by iTunes, but user-defined fields would not.

You can use any GENRE name you like in iTunes. However it will not separate them. So for Christmas / Blues / Subdued this will be exactly the single GENRE that is displayed (not separated).

Yes. I hope that at some point I would put those fields to use in the future but as MotleyG surmised they would show up as single fields with all the forward slashes.

If I could get a handle on foobar I am sure it would suit my needs but I do not have the time to deal with another app that comes with a large learning curve. IMatch is taking all I can give.

Meanwhile I am still trying to crack the puzzle of the second function. Currently writing a action that may work...

No need to be surprised, iTune has been notorious for resistant on the idea of having multi-value tags. I still remembered the time spent on salvaging my music library after multivalued ID3 v2.4 tags were all overwritten with random junk memory after iTune saves tag.

But no need to hurry, familiar youself with various tools first. You can switch player anytime when it feels right.

Apple has never suggested that iTunes would ever support multiple tag fields. But the same goes for many other players. What is important here is to recognize what the player of choice can do.

To get the second question addressed, you will have to start filtering by the number of separators you have in the genre. So wherever you have say four genres (so three slashes β€œ/β€œ) you can use this action
Guess values
Source: GENRE
Pattern: %genre1%/%genre2%/%genre3%/%genre4%

And do the same adjusting for more or less after filtering.

EDIT: I just noticed in your original post example that you have spaces before and following each slash. If you wish to avoid having these captured in the field data, make sure to include them in the pattern like below. Every character matters, even a space.
Pattern: %genre1% / %genre2% / %genre3% / %genre4%

1 Like

Here is a filter that should filter for the set number of slashes (3 in this case)
"$len($regexp(%genre%,'[^/]',))" IS 3

1 Like

Thanks guys! Sorry I was busy with other matters until now. So I will use ohrenkino's filter (THANK YOU! that will be very useful) and then use MotleyG's suggestion for an action. It will be laborious, doing it piece-meal but the pain will stop me for making the same mistake again. I really don't know why I erase information when I can always store it in a custom tag.

I was working on cleaning up my genres with the tools given by MotleyG & ohrenkino and realized that the script I was using to append genres

%genre%$if(%genre1%, / %genre1%,)$if(%genre2%, / %genre2%,)$if(%genre3%, / %genre3%,)$if(%genre4%, / %genre4%,)$if(%genre5%, / %genre5%,)$if(%genre6%, / %genre6%,)$if(%genre7%, / %genre7%,)$if(%genre8%, / %genre8%,)$if(%genre9%, / %genre9%,)$if(%genre10%, / %genre10%,)

had a flaw where if %genre1% was not populated, %genre% would start with a Forward Slash (/).

I modified it to work if genre1 was not populated, using this
$if(%genre1%,%genre1%,)$if($and(%genre1%,%genre2%), / ,)$if(%genre2%,%genre2%,) and so on...
But if %genre2% was not populated, then I would still have the forward slash and the beginning of %genre%.

I tired to write something that would instruct MP3Tag to only insert the forward slash if a genre existed and if any of the previous ones existed, but I could not get it to work.
I tried
$if($and(%genre3%,(%genre2%|%genre1)), / ,)
but that will result in a forward slash in the beginning of %genre% even if there is no %genre1% or %genre2%, so there must be something wrong with the script..

How could I change this to get the desired result?

I still think that these numerous user-defined fields are not really the best solution.


Try and action of the type "Format value" for GENRE
Format string: %genre%[ / %genre1%][ / %genre2%][ / %genre3%]
(and so on)