Rename a folder?

Hey guys. First off, I LOVE beets!!! I purchased Jaikoz years and years ago to organize my music collection but really never used it. Over the last week, I’ve used beets to organize most of my collection. Thanks for your hard work!

I think my question is simple enough, however searching the excellent docs just doesn’t help. I’d like to suggest more examples, if possible. I have a large collection of compilations, and would like to rename a few of the folders. For example, I have:

The Encyclopedia of Jazz, Part 1 5 - Classic Jazz - From New Orleans to Harlem

The actual album name has a slash between 1 and 5, however beets replaces this with a space (I changed it from an underscore). I’d like to rename it to:

The Encyclopedia of Jazz, Part 1 of 5 - Classic Jazz - From New Orleans to Harlem

Notice the “of”. If possible, I only want to rename the folder and not the metadata in the music files. However, if it’s an all or nothing solution, I’ll take it.

I think I need to use either move or edit, but unfortunately, I cannot find any examples.

Any advice would be appreciated.

Thanks!

Hi! The beets philosophy is that filenames are always generated by rules from fields, so you don’t modify them manually.

To do what you want, I’d suggest using modify to set a new field—let’s call it $altalbum instead of $album—to the “alternative” name for the album you want to use in filenames. Then use something like %ifdef{altalbum,$altalbum,$album} in your path format to use this name while falling back to the “real” album name.

Thanks for your reply. In that case, would I be able to just alter the album name from “… 1/5…” to “… 1 of 5…” then have beets update the paths? Or does this go against standard practice?

Yes, that will work and is fine! But it will also change the tags (by default, at least).

Sorry to bump and old thread (but I think this could be useful to newcomers anyway)

I was wondering if you could offer a step-by-step for renaming files/folders ‘the beets way’ please?

Reason: After using beets for a short time now I have several instances in my music-library folders where certain characters have been replaced to make the path/filename ‘safe’ - a process which I respect is necessary.

Some examples include:

  • Incubus\S.C.I.E.N.C.E_
  • Incubus\A Crow Left of the Murder.._
  • Incubus\Morning View\11 - Are You In_.mp3

i.e. for the first two examples a trailing dot ‘.’ was replaced, and a question mark ‘?’ in the last.

For what, I suppose, are aesthetic reasons only I would like to remove these characters from the file/folder names but retain the correct characters in the metadata.

I have since re-evaluated the replace section in the beets config and adjusted my needs accordingly, however I am still uncertain exactly how to proceed since I can’t edit the paths manually and just ‘update’ (modify) the beets database with the new path (at least not without doing it track by track!) and a re-import operation I tried flagged an album as a duplicate and ended up deleting the files (I assume during a move operation that, for whatever reason, went nowhere?!) – always backup your files people!

There’s also the question of how to deal with certain fringe cases going forward … just drop in a new regex pattern for a given scenario and remove it again once done?!


TL;DR: I recommend any newcomer to beets takes the time to learn and understand how the beets replace config works!


Thanks!

Here’s my current replace config (with added notes) for reference:

replace:
    '[\\/]': ~          # replace slashes with a tilde
    '\.{3,}' : …        # replace 3 or more dots with a true ellipse
    '^\.': ''           # replace a single leading dot with nothing (remove it)
    '[\x00-\x1f]': ''   # replace with nothing (i.e. remove)
    '[<>:"\?\*\|]': ''  # remove Windows restricted characters
    '\.$': ''           # remove single trailing dot
    '\s+$': ''          # remove trailing white-space
    '^\s+': ''          # remove leading white-space
    '^-': ''            # remove leading hyphen/dash

Yo! The thing to do is indeed to use beet move, which updates your filenames according to your current configuration. Did that give you any specific trouble?

It doesn’t seem to show a change despite the updated regex patterns…

Example: with Metadata value   Roni Size / Reprazent
Running:   beet move -ap reprazent

X:\Music\MP3\Artists\Roni Size _ Reprazent\[2000] In the Møde\14 - Centre of the Storm.mp3
  -> X:\Music\MP3\Artists\Roni Size _ Reprazent\[2000] In the Møde\14 - Centre of the Storm.mp3

Expected output:   ...\Roni Size ~ Reprazent\...

So either my regex is wrong, or beets isn’t recomputing the santised paths when only the config rules have changed, or it just isn’t showing it properly in the output?

Here’s my pathing config:

item_fields:
    # combine disc and track numbers for multi-disc albums (assuming <10 discs)
    disc_track: u'%01i_%02i' % (disc, track) if disctotal > 1 else u'%02i' % (track)
    # get the highest 'parent' genre -- note the separator (see lastgenre plugin)
    top_genre: |
        if genre:
            genres = genre.split(';')
            return genres[-1]
        else:
            return '_none_'

album_fields:
    # get certain album types to append in the folder name
    atype: |
        atypes = ['EP', 'DJ-mix']
        for atype in atypes:
            if atype.lower() == albumtype.lower():
                return f' [{atype}]'

paths:
    albumtype:soundtrack: OSTs/$album/$disc_track - $title
    default: Artists/$albumartist/[%if{$original_year,$original_year,$year}] ${album}${atype}%aunique{}/$disc_track - $title
    singleton: Loose Tracks/$top_genre/$albumartist/$artist - $title
    comp: Compilations/$album%aunique{}/$disc_track - $title

You’re running into a specific issue with replacing /, which is a special case, alas:

I see
…uh… please forgive my ignorance with regards to the inner workings going on here, I’m afraid I haven’t made much progress yet in ‘grokking’ the beets code-base, hence what I’m about to postulate…

Beets constructs the file-paths using the configured library folder in the config in tandem with a series of rules which essentially build up paths out of metadata … right? So, if a given metadata field (e.g. ‘title’) contains a possible path-separator character (such as a ‘/’) then surely beets can avoid confusing this character with an actual path-separator because it knows that it is coming from a metadata field?!

i.e. Run each piece of ‘path-building’ metadata through the user configured regex rules (replace: settings) before concatenating them together to form the final path, which for safety could then still be run through the full set of checks just to be doubly sure. In this way (and as per my example) the forward slash coming from the track’s ‘title’ field will have already been replaced with a tilde character before it becomes the final path-string for testing … which in this case will then never hit the path_sep_replace issue you mentioned.

Does that make sense or have I completely misunderstood the process?

@adrian Seriously thank you for your patience and help by the way it’s much appreciated. Your support of the community, and the larger community here itself, is impressive for a project of this nature :+1:

You haven’t misunderstood, and that’s basically how things work. To distill it, here’s what happens:

  1. Every individual field gets filtered with path_sep_replace.
  2. The filename is constructed with your configured path formats.
  3. The filename is sanitized for safety with replace.

Your proposal amounts to moving the replace action from step 3 to step 1. Unfortunately, that can’t quite work because there are (important!) replacement policies that depend on knowing the entire path, not just individual components at a time:

  • Less practically, imagine a replace setup that replaces ab with c, and a path format $foo$bar where $foo expands to xa and $bar expands to by. We would want the final result to be xcy, which requires sanitizing the complete path.
  • More practically, even in the default configuration, there’s a replacement for \.$ because trailing dots cause errors on Windows filesystems. The only way to know whether a dot will be in the trailing position of a path component is to sanitize the complete, expanded path.

Thanks…

Actually what I guess I was effectively proposing is that replace is used for step 1 and step 3

I’m still confused though, because surely if any sanitization operation replaces all path-separators with underscores on an entire path then that path would end up with no path-separators at all?! … so it must only operate on path segments at a time!

Referring to the documentation:

replace:
    '[\\/]': _
    ...etc.

This default rule replaces any instance of a forward-slash or back-slash with an underscore, but if this is allowed to operate on an entire path then surely…

a\beets\template\path-to\Roni Size _ Reprazent

…would end up as…

a_beets_template_path-to_Roni Size _ Reprazent

– respecting that path_sep_replace has operated before hitting the path-config


Sorry, I’m just trying to understand what’s going on with the path sanitizing   :confused:

No worries! Sanitization happens on path components, not entire paths. So the actual algorithm is, “split on /, then for each string between the /s, do the replace stuff.”

Either way though I realise that it is doing what it’s doing for a reason (probably several)
…regardless of whether I understand them or not   :smile:

So I wondered if I could come up with a bit of a dirty hack to allow me to update the path field for a given album, along the lines of…

beet update -aM -f path="A:\new\path\to\album-folder" match this query

…where

  • only the path field is updated (all others ignored / return error)
  • files are NOT moved (regardless of if the ‘M’ flag has been set)
    since they’ve already been moved
  • the albumart path reference is also updated

To that end I have created this gist to show my (very) rough attempt to implement this…
… please bear in mind I am really not yet very familiar with Python or beets   :worried:

To be clear, I don’t think you need to resort to hacks! I think you just need to change your path_sep_replace config option (despite the fact that it’s undocumented) and then do a normal beet move.

Aha… riiiight…  :woozy_face:
I’ll try that first then  :grin: :+1:

Cheers Adrian!

@adrian

How could we take advantage of the changes proposed here

Replace Forbidden Windows Symbols Plugin

Hmm, can you explain in more detail what the intent behind those changes is and what that means for beets? The PR thread is low on context.

Adrian,

I was looking to replace those illegal characters on windows, I can use all of the replacements apart from these four characters “* . | ?”. These do not work with the replacement function, even when escaped.

":": "∶"
    "/": "⁄"
#    "*": "∗"
#    "?": "?"
    '"': '″'
    '\\': "⧵"
#    '.': '․'
#    '|': 'ǀ'
    '<': '‹'
    '>': '›'

Looking at beets/util/__inint.py__L570-581 and the MS comment, we should also look at the reserved words in the article as well, if they are the only name for the file excluding extension.

In the current library all of those illegal windows characters are replaced before the replace function is called, as discussed above.

I am following the Picard plugins, as some of them are appropriate to beets.