Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

persist set_fields to media files #3927

Merged
merged 5 commits into from
May 14, 2021
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 28 additions & 21 deletions beets/importer.py
Original file line number Diff line number Diff line change
Expand Up @@ -572,18 +572,24 @@ def remove_duplicates(self, lib):
util.prune_dirs(os.path.dirname(item.path),
lib.directory)

def set_fields(self):
def set_fields(self, lib):
"""Sets the fields given at CLI or configuration to the specified
values.
values, for both the album and all its items.
"""
for field, view in config['import']['set_fields'].items():
value = view.get()
log.debug(u'Set field {1}={2} for {0}',
displayable_path(self.paths),
field,
value)
self.album[field] = value
self.album.store()
with lib.transaction():
items = self.imported_items()
for field, view in config['import']['set_fields'].items():
value = view.get()
log.debug(u'Set field {1}={2} for {0}',
displayable_path(self.paths),
field,
value)
self.album[field] = value
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The exact same loop as before, wrapped in a transaction plus amended with changing all items of the album.

for item in items:
item[field] = value
for item in items:
item.store()
self.album.store()
Comment on lines +590 to +592
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be sufficient for the transaction to extend only over these three lines, setting the fields above shouldn't interact with the database.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thx, fixed


def finalize(self, session):
"""Save progress, clean up files, and emit plugin event.
Expand Down Expand Up @@ -946,18 +952,19 @@ def choose_match(self, session):
def reload(self):
self.item.load()

def set_fields(self):
def set_fields(self, lib):
"""Sets the fields given at CLI or configuration to the specified
values.
values, for the singleton item.
"""
for field, view in config['import']['set_fields'].items():
value = view.get()
log.debug(u'Set field {1}={2} for {0}',
displayable_path(self.paths),
field,
value)
self.item[field] = value
self.item.store()
with lib.transaction():
for field, view in config['import']['set_fields'].items():
value = view.get()
log.debug(u'Set field {1}={2} for {0}',
displayable_path(self.paths),
field,
value)
self.item[field] = value
self.item.store()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The exact same loop as before, wrapped in a transaction.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It think there's no need for the transaction here, the only interaction with the database here is in item.store() which already uses a transaction internally.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thx. fixed.



# FIXME The inheritance relationships are inverted. This is why there
Expand Down Expand Up @@ -1516,7 +1523,7 @@ def apply_choice(session, task):
# because then the ``ImportTask`` won't have an `album` for which
# it can set the fields.
if config['import']['set_fields']:
task.set_fields()
task.set_fields(session.lib)


@pipeline.mutator_stage
Expand Down
2 changes: 2 additions & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,8 @@ Other new things:
``check_on_import`` config option.
* :doc:`/plugins/export`: big speedups when `--include-keys` option is used
Thanks to :user:`ssssam`.
* The `importer` persists all fields set using :ref:`set_fields` to the
mediafiles of all imported tracks.
* Added 7z support via the `py7zr`_ library
Thanks to :user:`arogl`. :bug:`3906`
* Get ISRC identifiers from musicbrainz
Expand Down
3 changes: 3 additions & 0 deletions docs/reference/config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -683,6 +683,9 @@ Here's an example::
Other field/value pairs supplied via the ``--set`` option on the command-line
override any settings here for fields with the same name.

Fields are set on both the album and each individual track of the album.
Fields are persisted to the media files of each track.

Default: ``{}`` (empty).

.. _musicbrainz-config:
Expand Down
12 changes: 11 additions & 1 deletion test/test_importer.py
Original file line number Diff line number Diff line change
Expand Up @@ -740,10 +740,12 @@ def test_asis_no_data_source(self):
def test_set_fields(self):
genre = u"\U0001F3B7 Jazz"
collection = u"To Listen"
comments = u"managed by beets"

config['import']['set_fields'] = {
u'collection': collection,
u'genre': genre
u'genre': genre,
u'comments': comments
}

# As-is album import.
Expand All @@ -755,6 +757,10 @@ def test_set_fields(self):
album.load() # TODO: Not sure this is necessary.
self.assertEqual(album.genre, genre)
self.assertEqual(album.collection, collection)
for item in album.items():
self.assertEqual(item.genre, genre)
self.assertEqual(item.collection, collection)
self.assertEqual(item.comments, comments)
# Remove album from library to test again with APPLY choice.
album.remove()

Expand All @@ -768,6 +774,10 @@ def test_set_fields(self):
album.load()
self.assertEqual(album.genre, genre)
self.assertEqual(album.collection, collection)
for item in album.items():
self.assertEqual(item.genre, genre)
self.assertEqual(item.collection, collection)
self.assertEqual(item.comments, comments)
Copy link
Member

@wisp3rwind wisp3rwind May 13, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you checked that this test fails without the above changes to set_fields? I suspect that due to #2988, this part of the test was already successful before; it doesn't verify that the item tags are actually set and would end up being written to Mediafile tags, though.

Maybe change to

Suggested change
for item in album.items():
self.assertEqual(item.genre, genre)
self.assertEqual(item.collection, collection)
self.assertEqual(item.comments, comments)
for item in album.items():
self.assertEqual(item.get("genre", with_album=False), genre)
self.assertEqual(item.get("collection", with_album=False), collection)
self.assertEqual(item.get("comments", with_album=False), comments)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I checked. It failed without the change. In particular, it would not set the comments. Nevertheless I have adopted your suggestion for a stricter get.



class ImportTracksTest(_common.TestCase, ImportHelper):
Expand Down