Repository: beetbox/beets

Issue:
Option to clear all fields before applying a match
An option/plugin to use only metadata from online sources. 
1. Don't import any of the files original tag data to the beets-database, only use this information to obtain matches from the online sources.
2. Completely clear/delete the entire existing tag before writing the new one.



Discussion:
This should be fairly straightforward to add. My only reservation is that it may not actually be what you (or most people) want, since metadata indices can sometimes be missing data.

Yes, you're right that this can lead to a loss of information in case of relatively well tagged mp3s. For my particular music collection however, it'd be a lot better to have some data missing than to leave the horrible tag content existing in many of my files.
I'd be very happy to have this option!

#1173 This would be nice!

I am very interested in implementing this, as the current metadata on my music collection is hot garbage. The genre tag is particularly problematic because musicbrainz doesn't set it, so I end up importing whatever genre was already tagged on the track. I'd much prefer beets to be the originator for all the tags that end up on my imported music.

I'd like to confirm my understanding of the problem before I work on a PR:

- the changes should be made in the apply_metadata function [here](https://github.com/beetbox/beets/blob/master/beets/autotag/__init__.py#L61) or somewhere in the callchain leading there ([ImportTask.apply_metadata](https://github.com/beetbox/beets/blob/master/beets/importer.py#L534) is around where I'm thinking).
- to achieve the desired effect, every [field](https://github.com/beetbox/beets/blob/master/beets/library.py#L424) in the Item should be zeroed before applying the matched metadata. This zeroing should only happen if the user actually chooses apply.
- a new configuration option (`import.from_scratch`) should be added to toggle the behavior globally, with a corresponding flag (`--from-scratch`) to toggle the behavior at runtime. Anyone want to bikeshed on the name of this?
- I need to add tests for all new functionality.

Resolving patch:
diff --git a/beets/importer.py b/beets/importer.py
--- a/beets/importer.py
+++ b/beets/importer.py
@@ -534,6 +534,10 @@ def imported_items(self):
     def apply_metadata(self):
         """Copy metadata from match info to the items.
         """
+        if config['import']['from_scratch']:
+            for item in self.match.mapping:
+                item.clear()
+
         autotag.apply_metadata(self.match.info, self.match.mapping)
 
     def duplicate_items(self, lib):
diff --git a/beets/library.py b/beets/library.py
--- a/beets/library.py
+++ b/beets/library.py
@@ -561,6 +561,11 @@ def update(self, values):
         if self.mtime == 0 and 'mtime' in values:
             self.mtime = values['mtime']
 
+    def clear(self):
+        """Set all key/value pairs to None."""
+        for key in self._media_fields:
+            setattr(self, key, None)
+
     def get_album(self):
         """Get the Album object that this item belongs to, if any, or
         None if the item is a singleton or is not associated with a
diff --git a/beets/ui/commands.py b/beets/ui/commands.py
--- a/beets/ui/commands.py
+++ b/beets/ui/commands.py
@@ -1004,6 +1004,10 @@ def import_func(lib, opts, args):
     u'-I', u'--noincremental', dest='incremental', action='store_false',
     help=u'do not skip already-imported directories'
 )
+import_cmd.parser.add_option(
+    u'--from-scratch', dest='from_scratch', action='store_true',
+    help=u'erase existing metadata before applying new metadata'
+)
 import_cmd.parser.add_option(
     u'--flat', dest='flat', action='store_true',
     help=u'import an entire tree as a single album'


Test patch:
diff --git a/test/test_importer.py b/test/test_importer.py
--- a/test/test_importer.py
+++ b/test/test_importer.py
@@ -633,6 +633,17 @@ def test_apply_candidate_adds_album_path(self):
         self.assert_file_in_lib(
             b'Applied Artist', b'Applied Album', b'Applied Title 1.mp3')
 
+    def test_apply_from_scratch_removes_other_metadata(self):
+        config['import']['from_scratch'] = True
+
+        for mediafile in self.import_media:
+            mediafile.genre = u'Tag Genre'
+            mediafile.save()
+
+        self.importer.add_choice(importer.action.APPLY)
+        self.importer.run()
+        self.assertEqual(self.lib.items().get().genre, u'')
+
     def test_apply_with_move_deletes_import(self):
         config['import']['move'] = True