Tagging script
General
These are working notes, not final shiny ready-for-the-world notes.
See also Rip / Tag
MusicBrainz Picard
wip
Notes
To make better through experience n nicking good ideas from the MB Picard forums.
To do:
- FAT problem?
- Characters to check; prince sign o the times, bjork. trentemoller, cruxshadows
- QT5 BUG - cannot copy and paste from here to picard without characters being altered!! - ISSUE WITH SWAY/WAYLAND - use X11/xwayland - resolved by now I guess? using just X11 atm.
- separate disc directories? more so for classical etc.
Move additional files:
*.png *.jpg *.jpeg *.gif *.tiff *.tif *.bmp *.apng *.mpg *.md *.pdf *.m3u *.m3u8 *.cue *.log *.sfv *.nfo *.txt *.rtf *.md5 *.accurip *.url *.thm *.doc *.docx *.odf *.otf *.auCDtect covers/ artwork/ art/ scan/ scans/ logs/ extras/
Some files in root dir with these extensions still don't copy? I give up on this front. Moving files in subdirectories is a known bug/feature request, IIRC.
Not just: *.jpg .jpeg *.png *.gif *.cue *.m3u
Why not *.* or *? [1]
Just use * then? tbc
Latest
$noop(requires: album-artist script) $noop(# define once what characters should be removed) $set(_unwantedchars,[’`'\\"”/\\-\\\\\\|;:\\*\\?!&\\[\\]\\{\\}\(\)<>\\\,\\._\$\\#]) $noop(# if the id of release is "Various Artists", or the release is a dj-mix, or there is a djmixer name present, return true) $set(_variousrelease,$if($or($eq(%musicbrainz_albumartistid%,89ad4ac3-39f7-470e-963a-56509c546377),$inmulti(%releasetype%,dj-mix),$ne(%djmixer%,)),true,)) $noop(# if this is a Various Artists release, prepare to return trackartist later in the file path) $set(_trackartist,$replace($strip($if(%_variousrelease%,$rreplace(%artist%,%_unwantedchars%,)-,)), ,_)) $noop(# artist path variable, sort out characters) $set(_releaseartist,$replace($strip($rreplace(%albumartist%,%_unwantedchars%,)), ,_)) $noop(# prefer earliest date in release group over release date, sort out spaces and delimiters) $set(_releasedate,$replace($if(%originaldate%,%originaldate%,%date%),-,_)-) $noop(# cat name, sort out characters) $set(_catalognumber,$replace($strip($rreplace(%catalognumber%,%_unwantedchars%,)), ,_)-) $noop(# release name, sort out characters) $set(_releasealbum,$replace($strip($rreplace(%album%,%_unwantedchars%,)), ,_)) $noop(# release disc number, sort out characters) $set(_releasediscnum,$if($gt(%totaldiscs%,1),$num(%discnumber%,$if($gt(%totaldiscs%,99),3,$if($gt(%totaldiscs%,9),2,1)))-,)) $noop(# release track number, sort out characters) $set(_releasetracknum,$num(%tracknumber%,$if($gt(%totaltracks%,99),3,2))) $noop(# release track name path variable, sort out characters.) $set(_releasetrack,$replace($strip($rreplace(%title%,%_unwantedchars%,)), ,_)) $noop(# build the full path up from the variables set above) %_releaseartist%/ %_releaseartist%-%_releasedate%%_catalognumber%%_releasealbum%/ %_releaseartist%-%_releasedate%%_releasealbum%-%_releasediscnum%%_releasetracknum%-%_trackartist%%_releasetrack%
Workings
- https://picard.musicbrainz.org/docs/scripting
- https://picard.musicbrainz.org/docs/tags
- https://docs.python.org/2/library/re.html#regular-expression-syntax
- https://community.metabrainz.org/t/repository-for-neat-file-name-string-patterns-and-tagger-script-snippets/2786
Problem with detecting a ""Various Artists"" disc - some releases do not use "Various Artists" for their %albumartist%, e.g., Fabric and Fabriclive DJ mix CDs.
Also, %albumartist% is equal to %artist% for regular %artist% releases.
Methods:
- Detect if %albumartist% equals "Various Artists"
$eq(x,y) # Returns true if x equals y.
$eq(%musicbrainz_albumartistid%,89ad4ac3-39f7-470e-963a-56509c546377)
- Detect if %releasetype% contains "compilation" or "dj-mix"
- Detect if %djmixer% contains anything.
$in(x,y) # Returns true, if x contains y. $inmulti(%x%,y) # Returns true if multi-value variable x contains exactly y as one of its values.
$eq_any(x,a1,a2...) # Returns true if x equals a1 or a2 or ... $or(x,y,*args) # Returns true if either x or y not empty. Can be used with an arbitrary number of args. $ne(x,y) # Returns true if x does not equal y. $or($inmulti(%releasetype%,compilation),$inmulti(%releasetype%,dj-mix),$ne(%djmixer%,))
$or($eq(%musicbrainz_albumartistid%,89ad4ac3-39f7-470e-963a-56509c546377),$inmulti(%releasetype%,compilation),$inmulti(%releasetype%,dj-mix),$ne(%djmixer%,)) $if(if,then,else) # If if is not empty, it returns then, otherwise it returns else. $if($or($eq(%musicbrainz_albumartistid%,89ad4ac3-39f7-470e-963a-56509c546377),$inmulti(%releasetype%,compilation),$inmulti(%releasetype%,dj-mix),$ne(%djmixer%,)),%albumartist%,%artist%)
$rreplace(text,pattern,replace) # Regular expression replace.
chars to remove: ’`'”-/\|;:*?!&[]{}<>,.$
special consideration:
- \ needs to be \\\\ to escape for both Picard and Python
- , needs to be \, because , is used to delineate arguments in $rreplace
- . needs to be \.
- $ needs to be \$
- * needs to be \*
- ? needs to be \?
- { needs to be \{
- [ needs to be \[
- | needs to be \|
- ( needs to be \(
- - needs to be \- because - is used in [5b-d] for 'between'
[’`'”\-/\\\\\|;:\*\?!&\[\]\{\}<>\,\.\$]
in progress mess:
Outer folder: $replace($validate($if(%albumartist%,%albumartist%,%artist%),,’`'”-/\|;:*?!&\[]{}<>,.)," ","_") becomes $set(_releaseartist,$replace($rreplace($if($or($eq(%musicbrainz_albumartistid%,89ad4ac3-39f7-470e-963a-56509c546377),$inmulti(%releasetype%,compilation),$inmulti(%releasetype%,dj-mix),$ne(%djmixer%,)),%albumartist%,%artist%),[’`'”\-/\\\\\|;:\*\?!&\[\]\{\}<>\,\.\$],) ,_)) %_releaseartist% / Release folder: $set(_releasealbum,$replace($rreplace(%album%,[’`'”\-/\\\\\|;:\*\?!&\[\]\{\}<>\,\.\$],) ,_)) %_releaseartist%-%date%-%_releasealbum% / Track file: $replace($validate($if(%albumartist%,%albumartist%,%artist%),,’`'”-/\|;:*?!&\[]{}<>,.)," ","_")-%year%-$replace($validate(%album%,,’`'”-/\|;:*?!&\[]{}<>,.)," ","_")-$num(%track%,2)$if(%albumartist%,-$replace($validate(%artist%,,’`'”-/\|;:*?!&\[]{}<>,.)," ","_"),)-$replace($validate(%title%,,’`'”-/\|;:*?!&\[]{}<>,.)," ","_") becomes $set(_releasetracknum,$if($gt(%totaldiscs%,1),%discnumber%-,)$num(%tracknumber%,$if($gt(%totaltracks%,99),3,2))) $set(_releasetrack,$replace($rreplace(%title%,[’`'”\-/\\\\\|;:\*\?!&\[\]\{\}<>\,\.\$],) ,_)) %_releasetracknum%-%_releasetrack%
So:
$set(_releaseartist,$replace($rreplace($if($or($eq(%musicbrainz_albumartistid%,89ad4ac3-39f7-470e-963a-56509c546377),$inmulti(%releasetype%,compilation),$inmulti(%releasetype%,dj-mix),$ne(%djmixer%,)),%albumartist%,%artist%),[’`'”\-/\\\\\|;:\*\?!&\[\]\{\}<>\,\.\$],) ,_)) %_releaseartist%/ $set(_releasealbum,$replace($rreplace(%album%,[’`'”\-/\\\\\|;:\*\?!&\[\]\{\}<>\,\.\$],) ,_)) %_releaseartist%-%date%-%_releasealbum%/ $set(_releasetracknum,$if($gt(%totaldiscs%,1),%discnumber%-,)$num(%tracknumber%,$if($gt(%totaltracks%,99),3,2))) $set(_releasetrack,$replace($rreplace(%title%,[’`'”\-/\\\\\|;:\*\?!&\[\]\{\}<>\,\.\$],) ,_)) %_releasetracknum%-%_releasetrack%
then I added more stuff
then I added
$num(%discnumber%,$if($gt(%totaldiscs%,9),2,1))-,)
Puddletag
- http://docs.puddletag.net/source/function.html
- http://docs.puddletag.net/source/scripting.html
- http://docs.puddletag.net/source/tags.html
older/alternative method, app looks like a spreadsheet. Uses MusicBrainz also.
Latest
Puddletag file spaces to underscores + albumartist ifs:
$replace($validate($if(%albumartist%,%albumartist%,%artist%),,’`'”-/\|;:*?!&\[]{}<>,.)," ","_")/$replace($validate($if(%albumartist%,%albumartist%,%artist%),,’`'”-/\|;:*?!&\[]{}<>,.)," ","_")-%year%-$replace($validate(%album%,,’`'”-/\|;:*?!&\[]{}<>,.)," ","_")/$replace($validate($if(%albumartist%,%albumartist%,%artist%),,’`'”-/\|;:*?!&\[]{}<>,.)," ","_")-%year%-$replace($validate(%album%,,’`'”-/\|;:*?!&\[]{}<>,.)," ","_")-$num(%track%,2)$if(%albumartist%,-$replace($validate(%artist%,,’`'”-/\|;:*?!&\[]{}<>,.)," ","_"),)-$replace($validate(%title%,,’`'”-/\|;:*?!&\[]{}<>,.)," ","_")
Path ends up like
KiloWatts/KiloWatts-2005-ProblemSolving/KiloWatts-2005-ProblemSolving-03-Scraped_On_the_Way_Out.flac
See Workings and Oldercrap for what this means
Remember to:
- avoid blank years
- avoid blank album/artist names
- check if some album artists should be "Various Artists" or a performer/DJ/curator name
- essentially all these are fixed by *carefully* running directories through MusicBrains prior
Testing
not working: $regex($regex($if(%albumartist%,%albumartist%,%artist%),’`'”-*\?!&/\|\\\(\)\[]\{\}<>;:,\.,),\s,_)/$regex($regex($if(%albumartist%,%albumartist%,%artist%)-%year%-%album%,’`'”-*\?!&/\|\\\(\)\[]\{\}<>;:,\.,),\s,_)/$regex($regex($if(%albumartist%,%albumartist%,%artist%)-%year%-%album%-$num(%track%,2)$if(%albumartist%,-%artist%,)-%title%,’`'”-*\?!&/\|\\\(\)\[]\{\}<>;:,\.,),\s,_) to fix ^ puddlestuff.findfunc.ParseError: SYNTAX ERROR in $regex: unbalanced parenthesis ??? vim-script shows balanced parens
Further issues(?):
- double __?
- remove accidental trailing whitespace?
Workings
Be careful when copying and pasting the above - a new line character might be added to the end.
Produces directory path and filenames like this:
/media/3tb/media/music/FLAC/Decapitated/Decapitated-2000-04-17-Winds_of_Creation/Decapitated-2000-04-17-Winds_of_Creation-05-Decapitated-The_Eye_of_Horus.flac
$validate(%title%,,’`'”-/\|;:*?!&\[]{}<>,.)
Cannot validate away ( or ) with the above method. Two regexs instead of validate and replace would allow changing ( and ). One for removing, one for underscores.
Functions cannot be applied across directory boundaries.
$regex(text, regex, repl, matchcase=0) Replaces all occurrences of regex with repl in text. text: text to search, eg. %artist% regex: regular expression to use as the search eg. jay.* repl: Text to replace all matches of regex with. Can be pattern ex $lower($1), but has to be quoted like in “$lower($1)” otherwise any scripting functions used will be run before the regular expression is evaluated. matchcase: Defaults to 0. If 1, will have case-sensitive matching. 's/ /_/g' $regex(,\s,_) chars to remove: ’`'”-*?!&/|\()[]{}<>;:,. unescaped: $regex(,’`'”-*?!&/|\()[]{}<>;:,.,) regex control chars: [\^$.|?*+(){}
not used: regex to make string filesystem safe?: ^(/)?([^/\0]+(/)?)+$
escaped: $regex(,’`'”-*\?!&/\|\\\(\)\[]\{\}<>;:,\.,) within removal of spaces $regex($regex(,’`'”-*\?!&/\|\\\(\)\[]\{\}<>;:,\.,),\s,_) | |
$if(%albumartist%,%albumartist%,%artist%)/ $if(%albumartist%,%albumartist%,%artist%)-%year%-%album%/ $if(%albumartist%,%albumartist%,%artist%)-%year%-%album%-$num(%track%,2)$if(%albumartist%,-%artist%,)-%title%
Older crap
basic formatting tests (see bottom for final);
Puddletag directory spaces to _: $replace($validate(%artist%,,’`'/\*?;”|:)," ","_")/$replace($validate(%artist%,,’`'/\*?;”|:)," ","_")-%year%-$replace($validate(%album%,,’`'/\*?;”|:)," ","_") Puddletag file spaces to _: $replace($validate(%artist%,,’`'/\*?;”|:)," ","_")-%year%-$replace($validate(%album%,,’`'/\*?;”|:)," ","_")-$num(%track%,2)-$replace($validate(%title%,,’`'/\*?;”|:)," ","_") Puddletag directory remove spaces: $validate($if(%albumartist%,%albumartist%,%artist%),,’`'/\*?;”|: )/$validate($if(%albumartist%,%albumartist%,%artist%),,’`'/\*?;”|: )-%year%-$validate(%album%,,’`'/\*?;”|: )/ Puddletag file remove spaces: $validate($if(%albumartist%,%albumartist%,%artist%),,’`'/\*?;”|: )-$if($neql(%artist%,%albumartist%),%artist%-,)%year%-$validate(%album%,,’`'/\*?;”|: )-$num(%track%,2)-$validate(%title%,,’`'/\*?;”|: ) $validate($if(%albumartist%,%albumartist%,%artist%),,’`'/\*?;”|: )-$if($neql(%artist%,%albumartist%),%artist%-,)%year%-$validate(%album%,,’`'/\*?;”|: )-$num(%track%,2)-$validate(%title%,,’`'/\*?;”|: ) redo: %artist%/%artist%-%year%-%album%/ %artist%-%year%-%album%-%track%-%title% %albumartist%/%albumartist%-%year%-%album%/ %albumartist%-%year%-%album%-%track%-%artist%-%title% $if(%albumartist%,%albumartist%,%artist%)/$if(%albumartist%,%albumartist%,%artist%)-%year%-%album%/$if(%albumartist%,%albumartist%,%artist%)-%year%-%album%-%track%$if(%albumartist%,-%artist%,)-%title% $validate(,,’`'”-/\|;:*?!&\[]<>,.)
Schema: albumartist = various artists compilation album. An if to see if albumartist and artist is different would fail for compilations including a track by the album artist.
Final:
Puddletag file remove spaces + albumartist ifs: $validate($if(%albumartist%,%albumartist%,%artist%),,’`'/\*?;”|: -&\[],.)/$validate($if(%albumartist%,%albumartist%,%artist%),,’`'/\*?;”|: -&\[],.)-%year%-$validate(%album%,,’`'/\*?;”|: -&\[],.)/$validate($if(%albumartist%,%albumartist%,%artist%),,’`'/\*?;”|: -&\[],.)-%year%-$validate(%album%,,’`'/\*?;”|: -&\[],.)-$num(%track%,2)$if(%albumartist%,-$validate(%artist%,,’`'/\*?;”|: -&\[],.),)-$validate(%title%,,’`'/\*?;”|: -&\[],.)
Produces directory path and filenames like this:
/media/3tb/media/music/FLAC/Decapitated/Decapitated-2000-04-17-WindsofCreation/Decapitated-2000-04-17-WindsofCreation-05-Decapitated-TheEyeofHorus.flac
New final:
Puddletag file spaces to underscores + albumartist ifs: $replace($validate($if(%albumartist%,%albumartist%,%artist%),,’`'/\*?;”|:-&\[],.)," ","_")/$replace($validate($if(%albumartist%,%albumartist%,%artist%),,’`'/\*?;”|:-&\[],.)," ","_")-%year%-$replace($validate(%album%,,’`'/\*?;”|:-&\[],.)," ","_")/$replace($validate($if(%albumartist%,%albumartist%,%artist%),,’`'/\*?;”|:-&\[],.)," ","_")-%year%-$replace($validate(%album%,,’`'/\*?;”|:-&\[],.)," ","_")-$num(%track%,2)$if(%albumartist%,-$replace($validate(%artist%,,’`'/\*?;”|:-&\[],.)," ","_"),)-$replace($validate(%title%,,’`'/\*?;”|:-&\[],.)," ","_")
How does evaluation work? test:
$replace($validate($if(%albumartist%,%albumartist%,%artist%)/$if(%albumartist%,%albumartist%,%artist%)-%year%-%album%/$if(%albumartist%,%albumartist%,%artist%)-%year%-%album%-%track%$if(%albumartist%,-%artist%,)-%title%,,’`'/\*?;”|:-&\[],.)," ","_")
Ah, evaluation stops at directory slashes.
Issues(?):
- double __?
- remove accidental trailing whitespace?
- paren brackets