ignore item-only fields configured in albumfields

This commit is contained in:
Alok Saboo
2026-07-12 20:14:11 -04:00
parent f91ba3a315
commit 210ca09637
2 changed files with 40 additions and 0 deletions

View File

@@ -16,6 +16,7 @@ from beets import plugins, ui, util
from beets.dbcore import types
from beets.exceptions import UserError
from beets.importer import Action
from beets.library import Album
from beets.ui.commands.utils import do_query
from beets.util import PromptChoice
@@ -348,6 +349,21 @@ class EditPlugin(plugins.BeetsPlugin):
if not album_fields:
return None
# Restrict to fields that actually exist on the Album model. Item
# has every Album field plus track-only ones (title, track, path,
# ...); since the header is built from a single item and then
# applied to every item, an item-only field here would silently
# stamp that one item's value onto the whole album.
invalid_fields = album_fields - Album._field_names
if invalid_fields:
self._log.warning(
"ignoring albumfields not valid for albums: {}",
", ".join(sorted(invalid_fields)),
)
album_fields &= Album._field_names
if not album_fields:
return None
first_item = task.items[0]
header = flatten(first_item, album_fields)
return header if header else None

View File

@@ -455,6 +455,30 @@ class EditDuringImporterNonSingletonTest(EditDuringImporterTestCase):
assert all("Edited Track" in i.title for i in self.lib.items())
def test_importer_edit_album_header_ignores_item_only_fields(self):
"""`albumfields` may be misconfigured with item-only fields (e.g.
`track`, `title`, `path`) that vary per track. Those must not end
up in the header, since the header gets applied to every item and
would otherwise stamp one track's values onto the whole album.
"""
self.prepare_album_for_import(3)
self.items_orig = [Item.from_path(f.path) for f in self.import_media]
self.config["edit"]["itemfields"] = "track title artist album"
self.config["edit"]["albumfields"] = "album albumartist track title"
self.run_mocked_interpreter(
{"replacements": {"Tag Album": "Modified Album"}},
# eDit, Apply changes.
["d", "a"],
)
titles = [i.title for i in self.lib.items()]
tracks = [i.track for i in self.lib.items()]
assert len(set(titles)) == len(titles)
assert len(set(tracks)) == len(tracks)
assert all(i.album == "Modified Album" for i in self.lib.items())
def test_importer_edit_album_header_albumartist(self):
"""Edit albumartist in the header (default albumfields)."""
self.run_mocked_interpreter(