MP3 Tagging Failure - `WOAF`
Hi there, thanks for this amazing plugin that has vastly improved my library management experience! 🥳 I don't have experience with the mechanics of audio tagging so I thought I would ask here to learn more.
TLDR: I am not able to tag source MP3 audiobook files without commenting out this line, after which it seems to work.
With that line attempting to read the WOAF tag, this is the error I encounter (appears to originate from the mediafile dependency. I tested with a variety of MP3 source audiobooks, all of which cause the error to appear. Example:
❯ tree
.
└── 2008 - House of Suns
├── desc.txt
├── House of Suns (2008) - cover.jpg
├── House of Suns (2008) - pt01.mp3
├── House of Suns (2008) - pt02.mp3
├── House of Suns (2008) - pt03.mp3
├── House of Suns (2008) - pt04.mp3
├── House of Suns (2008) - pt05.mp3
├── House of Suns (2008) - pt06.mp3
├── House of Suns (2008) - pt07.mp3
├── House of Suns (2008) - pt08.mp3
├── House of Suns (2008) - pt09.mp3
├── House of Suns (2008) - pt10.mp3
├── House of Suns (2008) - pt11.mp3
├── House of Suns (2008) - pt12.mp3
├── House of Suns (2008) - pt13.mp3
├── House of Suns (2008) - pt14.mp3
├── House of Suns (2008) - pt15.mp3
├── House of Suns (2008) - pt16.mp3
├── reader.txt
└── Thumbs.db
2 directories, 20 files
❯ beet import --timid "2008 - House of Suns"
Traceback (most recent call last):
File "/home/noah/.local/share/mise/installs/python/3.12.7/bin/beet", line 8, in <module>
sys.exit(main())
^^^^^^
File "/home/noah/.local/share/mise/installs/python/3.12.7/lib/python3.12/site-packages/beets/ui/__init__.py", line 1870, in main
_raw_main(args)
File "/home/noah/.local/share/mise/installs/python/3.12.7/lib/python3.12/site-packages/beets/ui/__init__.py", line 1849, in _raw_main
subcommand.func(lib, suboptions, subargs)
File "/home/noah/.local/share/mise/installs/python/3.12.7/lib/python3.12/site-packages/beets/ui/commands.py", line 1398, in import_func
import_files(lib, paths, query)
File "/home/noah/.local/share/mise/installs/python/3.12.7/lib/python3.12/site-packages/beets/ui/commands.py", line 1329, in import_files
session.run()
File "/home/noah/.local/share/mise/installs/python/3.12.7/lib/python3.12/site-packages/beets/importer.py", line 360, in run
pl.run_parallel(QUEUE_SIZE)
File "/home/noah/.local/share/mise/installs/python/3.12.7/lib/python3.12/site-packages/beets/util/pipeline.py", line 446, in run_parallel
raise exc_info[1].with_traceback(exc_info[2])
File "/home/noah/.local/share/mise/installs/python/3.12.7/lib/python3.12/site-packages/beets/util/pipeline.py", line 260, in run
msg = next(self.coro)
^^^^^^^^^^^^^^^
File "/home/noah/.local/share/mise/installs/python/3.12.7/lib/python3.12/site-packages/beets/importer.py", line 1444, in read_tasks
yield from task_factory.tasks()
File "/home/noah/.local/share/mise/installs/python/3.12.7/lib/python3.12/site-packages/beets/importer.py", line 1267, in tasks
tasks = self._create(self.album(paths, dirs))
^^^^^^^^^^^^^^^^^^^^^^^
File "/home/noah/.local/share/mise/installs/python/3.12.7/lib/python3.12/site-packages/beets/importer.py", line 1347, in album
items = [item for item in items if item]
^^^^^
File "/home/noah/.local/share/mise/installs/python/3.12.7/lib/python3.12/site-packages/beets/importer.py", line 1396, in read_item
return library.Item.from_path(path)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/noah/.local/share/mise/installs/python/3.12.7/lib/python3.12/site-packages/beets/library.py", line 697, in from_path
i.read(path)
File "/home/noah/.local/share/mise/installs/python/3.12.7/lib/python3.12/site-packages/beets/library.py", line 811, in read
value = getattr(mediafile, key)
^^^^^^^^^^^^^^^^^^^^^^^
File "/home/noah/.local/share/mise/installs/python/3.12.7/lib/python3.12/site-packages/mediafile.py", line 1254, in __get__
out = style.get(mediafile.mgfile)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/noah/.local/share/mise/installs/python/3.12.7/lib/python3.12/site-packages/mediafile.py", line 492, in get
return self.deserialize(self.fetch(mutagen_file))
^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/noah/.local/share/mise/installs/python/3.12.7/lib/python3.12/site-packages/mediafile.py", line 769, in fetch
return mutagen_file[self.key].text[0]
^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'WOAF' object has no attribute 'text'
Am I misconfiguring something that would allow the graceful reading of a null WOAF tag for MP3 files or can it be skipped?
I did notice that this fetch implementation is unique to the
MP3StorageStyleclass but I personally lack the context to comprehend the rationale or implications in this application.
Sorry for the late reply. I've not seen this issue before, since most of my stuff isn't mp3. That said, I still do have mp3 files and don't remember ever seeing that error.
There isn't any configuration option to disable use of that tag, since this is the first I've heard of this.
Good to know, thanks for sharing! I know this might just be an issue with my files so I'll continue using my own version as we hear more from other users
You can also consider opening an issue in the Mediafile repository as well, since this plugin uses it as a dependency.
Ok I've just ran into this as well. This must be a regression because I've tagged these files before with a previous Beets version which worked, but now it doesn't.
workaround:
change this line:
https://github.com/beetbox/mediafile/blob/master/mediafile.py#L770
and add AttributeError to the except
def fetch(self, mutagen_file):
try:
return mutagen_file[self.key].text[0]
except (KeyError, IndexError, AttributeError):
return None
I did some more investigations: root-cause is that WOAF field (sometimes?) don't have a text attribute but a url attribute. This seems not be supported in mediafile lib.
Update: I created a possible fix and opened a PR: https://github.com/beetbox/mediafile/pull/83
Thanks for looking into this. I'll bump the mediafile dependency once its fixed there.
I've released v1.0.2 with a workaround for this. It disables use of the WOAF tag for mp3 files, pending a proper fix.