Rename rules for single songs from an album

I have a lot of “albums” where only one or two tracks actually exist in my collection. In that case, I’m thinking it makes more sense to place them directly under the “Artist” folder rather than the typical “Artist/Album” location, and to omit the track number. For a rule, maybe something along the lines of “if less than 25% of the album is present, save the tracks directly under the Artist” (or possibly with different rules for shorter albums such as 12" singles or EPs).

Something like:

> Artist
> Artist > Album 1
> Artist > Album 1 > 01 Track 1
> Artist > Album 1 > 02 Track 2
> Artist > Album 1 > 09 Track 9
> Artist > Lonely Track 1
> Artist > Lonely Track 2 (came from album 2, but I only had the two tracks)

I was looking into custom naming scripts, but in order to apply my rule I think I need a bit of additional information. Basically, I need the number of tracks actually present on the album (or possibly a “percent complete” number). I also looked into writing a plugin that would add a variable for that information, but I wasn’t sure how to approach that. I can figure out how to make a plugin and a script, but I’m not sure what data is available and when, in order to tie the tracks to the albums.

Has anyone done something like this already? Any advice on a general approach I could take to accomplish this?

You can access the number of matched files using the $matchedtracks() function and the total number of tracks on a release (across all media) with the variable %_totalalbumtracks%.

Please note that $matchedtracks() only works when run as part of a file naming script, it will not give proper results when run from a regular tagger script (the ones in Options > Scripting).

What might be a bit difficult in regards to the idea of a “percent complete” number might be that Picard’s scripting arithmetic does only deal with integers. A simple approach might be to check for 50% might be:

$if($lt($matchedtracks(),$div(%_totalalbumtracks%,2)),do the single track renaming here,do the album track renaming here)

The $div(%_totalalbumtracks%,2) I think will work reasonable well.

More accuracy could be achieved with specialized functions, maybe having a $percentage(number,total) function or a function for actual floating point division. If you know a bit of Python then you could create a plugin that adds a new scripting function. That is one of the more easy plugins to do actually, see the documentation on Plugins API: Tagger Script Functions.


If you dont know python, I was terribly bored during a lecture and made a plugin for you. You can use it directly or just take inspiration from it.

Besides the $percentage(number,total) function suggested by outsidecontext, I added a function $percentage_matched() which gives you the percentage of tracks matched for each tracks’ album.

Like outsidecontext said, you can only use this second function as part of a file naming script. You can use it like this:

$if($lt($percentage_matched(),25),do the single track renaming here,do the album track renaming here)

Thanks @outsidecontext and @twodoorcoupe! That’s exactly what I needed. I had no idea there was already a $matchedtracks() function. Thanks also for going to the trouble to create a plugin and provide examples!

I’ll update with the naming script I end up using eventually, after more experimentation.


After getting this advice (thanks again) and digging further, I went down the rabbit hole of naming scripts and discovered how powerful they are. Basically you can implement any naming convention you want, no matter how complex, with a bit of scripting.

To my original question, we can find the percentage matched with the formula “matchedtracks() * 100 / %_totalalbumtracks%”, which lets me do something like the following:


That means, set a “_standalone” variable that I can use later in naming, if the number of matched tracks is 1 (or 0, in the case of unmatched tracks), OR if the number of matched tracks is 2 or less and that represents 25% of the total tracks or less.

I started out with that logic, and used it to omit the album folder and the track numbering, just putting the singles directly under the artist folder. After I experimented with that a bit I decided I’d rather see the album any time two or more tracks are present, so ultimately I discarded that “percentage matched” concept and simply considered it standalone when 1 or less tracks are matched.

But then I started adding a bunch of other rules, so I’ll post the full script in a followup post…


So after the rabbit hole of scripting, I ended up thinking up a bunch more rules:

  • Separate [A Capella] parent folder for acapella (like college groups or The Sing Off), identified by a tag that I set with a separate script run manually
  • [Soundtrack] parent folder for soundtracks
  • [Various Artists] parent folder for compilations
  • Use sort order artist name for the folder (“Beatles, The”, or “Joel, Billy”)
  • Remove featured artists from folder name (“Bob feat. Joe” → “Bob”)
  • Put the release year before the album title so they sort in chronological order (soundtracks or compilations put the year last so they sort by name)
  • Flag singles/EPs with an indicator after the year
  • Omit album folder and track number if only one album track is present
  • When the artist doesn’t match the album artist, add the artist to the track name
  • Add [YYYY Remaster] showing the year for remastered tracks (see note at bottom of this post)
  • Add [live] for live recordings
  • Replace special characters Windows doesn’t like, or which cause confusion, such as curly quotes, question marks, colons (and use two single quotes instead of a double quote)

Result is something like this:

> [Various Artists] > Album [Year] > 01 TrackName.mp3 
> Artist > [Year] Album > 01 TrackName.mp3
> Artist > [Year-Single] Album > 01 TrackName [ArtistName] [live].mp3
> Artist > StandaloneTrack.mp3

I ended up setting a bunch of variables up front to reduce the complexity of the actual naming part. Here’s the full script I ended up with:

$noop(Renaming script... some special rules
- If Grouping=acapella, use folder [A Capella] -- can use 'Tag as acapella' tagger script but ** DON'T LEAVE IT ON **
- If release type contains 'soundtrack', use folder [Soundtrack]
- If album artist is 'Various Artists', use folder [Various Artists]
- Use sort order artist name, and remove 'feat. xxx' and 'vs. xxx'
- Prepend [year] to album title, or append [year] in the case of soundtrack/various artist
- If releasetype is 'single' or 'ep', add -Single or -EP to the year, so it sorts after that year
- If only one matched track, omit album and track number [originally also used: or if 2 or less matched tracks AND that's <= 25 percent of the total]
- If the album artist doesn't match the artist, include the artist in the track name
- If RemasterDate tag is present, add [nnnn Remaster] suffix
- If release type contains 'live', append [live] to title
- Special character replacements: Remove'?', quote => double single quote, colon => dash with spaces

[A Capella]/ArtistName/[Year] AlbumName/01 TrackName.mp3
[Soundtrack]/AlbumName [Year]/01 TrackName.mp3
[Soundtrack]/AlbumName [Year]/StandaloneTrack.mp3
[Various Artists]/AlbumName [Year]/01 TrackName [ArtistName].mp3
[Various Artists]/AlbumName [Year]/StandaloneTrack [ArtistName].mp3
ArtistName/[Year] AlbumName/01 TrackName.mp3
ArtistName/[Year-Single] AlbumName/01 TrackName [ArtistName].mp3

$noop(Some derived boolean values)
$set(_various,$eq(%albumartist%,Various Artists))


$noop(Derive artist name and tweak for folder name)
$set(_artist,$rreplace($if2(%albumartistsort%,%artistsort%,%albumartist%,%artist%), \([Ff]eat\\.\).+\$|\(vs\\.\).+\$,))

$noop(Adjust special characters in album name)
$set(_album,$replace($get(_album),: , - ))

$noop(Adjust special characters in song title)
$set(_title,$replace($get(_title),: , - ))

$set(_trackNumber,$if($get(_showTrackNumber),$if($gt(%totaldiscs%,1),$if($gt(%totaldiscs%,9),$num(%discnumber%,2),%discnumber%)-,)$if($and(%albumartist%,%tracknumber%),$num(%tracknumber%,2) ,)))

$noop(The actual naming is here)
$if($eq($get(Grouping),acapella),[A Capella]/)
$if($get(_soundtrack),[Soundtrack],$if($get(_various),[Various Artists],$get(_artist)))/
$if($get(_showAlbumFolder),$if($get(_dateFirst),$get(_dateInfo) )$get(_album)$if($not($get(_dateFirst)), $get(_dateInfo))/)
$get(_trackNumber)$get(_title)$if($get(_showArtistInTitle), [%artist%])$if($get(RemasterDate), [$get(RemasterDate) Remaster])$if($get(_live), [live])

$noop(Enable this by changing "," to "1," to show debug details in the bottom panel of the script editor)
$if(,[TEST=$get(_standalone) $get(genre): $matchedtracks() of %_totalalbumtracks% = $div($mul($matchedtracks(),100),%_totalalbumtracks%)\%])

A note about remasters: I have a lot of files purchased from Amazon that say things like “[2018 Remaster]” in their title, and I bought them specifically because they sound better (I know that’s not always the case, but a lot of things were mixed pretty badly in the 80’s). So I want to know this, but MusicBraniz typically doesn’t track it.

So here’s what I did: I made a script (not a naming script) that I run manually when tracks are in the Picard “middle panel” (select all, right-click run scripts…). The script is called “Set RemasterDate from title [run before match]”. It needs to be run from that panel, because once it is matched to a release in the right panel, the original title is no longer available for scripting. This script uses regular expressions to extract the year from any title that contains the word “Remaster” (a year before that word, after that word, or just the year of the release if the title doesn’t mention a year). The result is stored in a custom tag called RemasterDate, which the above naming script uses to add “[YYYY Remaster]” back to the end of the track name.

$if($in($get(title),Remaster),$set(RemasterDate,$if2($rsearch($get(title),\(\\d{4}\) Remaster),$rsearch($get(title),Remaster?e?d \(\\d{4}\)),$left(%date%,4))))

So now I have everything just as I would like it (at least until I find the next thing I want to tweak). Cool!


Congratulations for getting everything to work the way you want it to and thank you for sharing the result!

That is me for the last four years, welcome to the club :sweat_smile: