diff --git a/beets/library.py b/beets/library.py index 64f67b511..1cdc1d408 100644 --- a/beets/library.py +++ b/beets/library.py @@ -217,6 +217,7 @@ class Item(object): """Writes the item's metadata to the associated file. """ f = MediaFile(syspath(self.path)) + plugins.send('write', item=self, mf=f) for key in ITEM_KEYS_WRITABLE: setattr(f, key, getattr(self, key)) f.save() diff --git a/beetsplug/scrub.py b/beetsplug/scrub.py new file mode 100755 index 000000000..d432643db --- /dev/null +++ b/beetsplug/scrub.py @@ -0,0 +1,83 @@ +# This file is part of beets. +# Copyright 2011, Adrian Sampson. +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. + +"""Cleans extraneous metadata from files' tags via a command or +automatically whenever tags are written. +""" +from __future__ import with_statement + +import logging + +from beets.plugins import BeetsPlugin +from beets import ui +from beets import mediafile +from beets import util + +log = logging.getLogger('beets') + +AUTOSCRUB_KEY = 'autoscrub' + +scrubbing = False + +options = { + AUTOSCRUB_KEY: True, +} +class ScrubPlugin(BeetsPlugin): + """Removes extraneous metadata from files' tags.""" + def configure(self, config): + options[AUTOSCRUB_KEY] = \ + ui.config_val(config, 'scrub', AUTOSCRUB_KEY, True, bool) + + def commands(self): + def scrub_func(lib, config, opts, args): + # This is a little bit hacky, but we set a global flag to + # avoid autoscrubbing when we're also explicitly scrubbing. + global scrubbing + scrubbing = True + + # Walk through matching files and remove tags. + for item in lib.items(ui.decargs(args)): + log.info(u'scrubbing: %s' % util.displayable_path(item.path)) + mf = mediafile.MediaFile(item.path) + _scrub(mf) + mf.save() + + if opts.write: + log.debug(u'writing new tags after scrub') + item.write() + + scrubbing = False + + scrub_cmd = ui.Subcommand('scrub', help='clean audio tags') + scrub_cmd.parser.add_option('-W', '--nowrite', dest='write', + action='store_false', default=True, + help='leave tags empty') + scrub_cmd.func = scrub_func + + return [scrub_cmd] + +def _scrub(mf): + """Remove all tags from a MediaFile by manipulating the underlying + Mutagen object. + """ + mf.mgfile.delete() + # Reinitialize the MediaFile: also a little hacky. + mf.__init__(mf.path) + +# Automatically embed art into imported albums. +@ScrubPlugin.listen('write') +def write_item(item, mf): + if not scrubbing and options[AUTOSCRUB_KEY]: + log.debug(u'auto-scrubbing %s' % util.displayable_path(item.path)) + _scrub(mf) diff --git a/docs/changelog.rst b/docs/changelog.rst index 320eecd4e..713d65b9e 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -25,6 +25,8 @@ This release focuses on making beets' path formatting vastly more powerful. directory and music file names. See :doc:`/reference/config`. * Beets now ensures that files have **unique filenames** by appending a number to any filename that would otherwise conflict with an existing file. +* The new :doc:`/plugins/scrub/` can remove extraneous metadata either manually + or automatically. * The autotagging heuristics have been tweaked in situations where the MusicBrainz database did not contain track lengths. Previously, beets penalized matches where this was the case, leading to situations where diff --git a/docs/plugins/index.rst b/docs/plugins/index.rst index 9e0faaaf5..55d80e089 100644 --- a/docs/plugins/index.rst +++ b/docs/plugins/index.rst @@ -43,6 +43,7 @@ disabled by default, but you can turn them on as described above: lastgenre replaygain inline + scrub .. _other-plugins: @@ -204,6 +205,9 @@ currently available are: singleton to the library (not called for full-album imports). Parameters: ``lib``, ``item``, ``config`` +* *write*: called with an ``Item`` and a ``MediaFile`` object just before a + file's metadata is written to disk. + The included ``mpdupdate`` plugin provides an example use case for event listeners. Extend the Autotagger diff --git a/docs/plugins/scrub.rst b/docs/plugins/scrub.rst new file mode 100644 index 000000000..9c3ebece5 --- /dev/null +++ b/docs/plugins/scrub.rst @@ -0,0 +1,41 @@ +Scrub Plugin +============= + +The ``scrub`` plugin lets you remove extraneous metadata from files' tags. If +you'd prefer never to see crufty tags that come from other tools, the plugin can +automatically remove all non-beets-tracked tags whenever a file's metadata is +written to disk by removing the tag entirely before writing new data. The plugin +also provides a command that lets you manually remove files' tags. + +Automatic Scrubbing +------------------- + +To automatically remove files' tags before writing new ones, just +enable the plugin (see :doc:`/plugins/index`). When importing new files (with +``import_write`` turned on) or modifying files' tags with the ``beet modify`` +command, beets will first strip the tags entirely and then write the +database-tracked metadata to the file. + +This behavior can be disabled with the ``autoscrub`` config option (see below). + +Manual Scrubbing +---------------- + +The ``scrub`` command provided by this plugin removes tags from files and then +rewrites their database-tracked metadata. To run it, just type ``beet scrub +QUERY`` where ``QUERY`` matches the tracks to be scrubbed. Use this command with +caution, however, because any information in the tags that is out of sync with +the database will be lost. + +The ``-W`` (or ``--nowrite``) option causes the command to just remove tags but +not restore any information. This will leave the files with no metadata +whatsoever. + +Configuring +----------- + +The plugin has one configuration option, ``autoscrub``, which lets you disable +automatic metadata stripping. To do so, add this to your ``~/.beetsconfig``:: + + [scrub] + autoscrub: no