mutagen icon indicating copy to clipboard operation
mutagen copied to clipboard

Unable to revert tag changes with backup variable / save() does not apply changes to file

Open Baalon opened this issue 7 months ago • 1 comments

Hello,

I am attempting to update some tags on audio files and I use user input to validate / revert changes. My issue is that .save() actually never saves the tags after I revert the tags to a backed up state, and ends up leaving my file without tags as I use .delete() to get a clean state and remove tags that I don't care about.

Here's my code (simplified, example using a FLAC file for file_path):

import copy
import mutagen

def get_new_file_metadata((file):
  file.delete() # get rid of unwanted tags, e.g., cover art

  # re assign all the tags to keep with updated values
  album = file_path.split("/")[-2].split(". ")[1].split(" (")[0].split(" [")[0]
  file.tags["ALBUM"] = album

def main (file_path):
  file = mutagen.File(file_path)
  old_tags = copy.deepcopy(file.tags)

  print("===== Old tags ====")
  print(old_tags.pprint())
  print("=========")

  get_new_file_metadata(file)

  print("===== New tags ====")
  print(file.tags.pprint())
  print("=========")

  user_validation = input('Confirm metadata change (Y/n): ').strip() or "Y"
  if user_validation != "Y":
    file.tags = old_tags
  file.save()

If I validate the changes, then everything works great, but if I do not, the file ends up with all the tags erased. The "file" variable itself seems to contain the metadata, and print(file.tags.pprint()) still works after file.tags = old_tags but file.save() does not.

I am using Python 3.12.3 and Mutagen 1.47.0

I suppose one workaround could be to specifcally look for every tag I do not want and .pop() them after user validation, but it is quite bothersome.

Anyway, let me know if it is actually a bug or if there's something wrong with my code

Cheers

Baalon avatar May 04 '25 10:05 Baalon

The problem is that you are messing with the internal structure of the FLAC class. The tags property is not supposed to be set directly. When loading data from a FLAC it is an instance of VCFLACDict, which also is internally referenced in a list of loaded blocks to write back to the file.

When you call file.delete() both references are removed. When you do file.tags = something you only set those tags.

If file.tags is None you should instead run file.add_tags() and then fill the tags on the newly created file.tags (and not replace it).

phw avatar Jun 16 '25 07:06 phw

Closing this as answered, see my answer above on how to properly handle the file.

phw avatar Aug 16 '25 08:08 phw