diff --git a/README.md b/README.md index 6cbf0c4..322fe0f 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ # Beets Extended Metadata Plugin This is a plugin for the music management tool [beets](https://beets.io).
-This plugin extends beets with a sub command that lets you write [Extended Metadata](https://github.com/calne-ca/beets-plugin-extended-metadata/blob/master/EMD.md) to your audio files. -It also extends beets query capabilities, allowing you to query your music library based on Extended Metadata. +This plugin adds [Extended Metadata](https://github.com/calne-ca/beets-plugin-extended-metadata/blob/master/EMD.md) capabilities to beets. +It extends the beets query syntax, allowing you to query songs based on Extended Metadata and also allows you to write, update and view Extended Metadata based on queries ## Setup @@ -99,16 +99,16 @@ This assumes you have a custom tag *language* containing the language of the son beet list x:.language:japanese x:.origin:'!japan' year:2010..2020 ```` -In this example you can see how to easily combine extended metadata queries with normal audio field queries. +In this example you can see how to easily combine Extended Metadata queries with normal audio field queries. It also shows how to negate query values. If you prefix the query tag value with ! it will mean *not equals* / *not contains*. -### Writing Extended Metadata +### Managing Extended Metadata The query capabilities work as long as the Extended Metadata has been written to the files according to the [Extended Metadata documentation](EMD.md). This means it is not required to use this plugin to write the Extended Metadata to your files. -The plugin provides an *emd* subcommand to write and update Extended Metadata based on beets queries. -The sub command requires a beets query that matches the items you want to edit and a list of options that define what you want to do. +The plugin provides an *emd* subcommand to write, update and show Extended Metadata based on beets queries. +The sub command requires a beets query that matches the items you want to apply options to, and a list of options that define what you want to do. To get an overview of all options you can use the *--help* option: ```shell @@ -121,9 +121,8 @@ Options: a beets query that matches the items to which the actions will be applied to. -u UPDATE_EXPRESSION, --update=UPDATE_EXPRESSION - update or move a tag value. Example: - "tag1:v1/tag1:v2" or "tag1:v1/tag2:v1" or - "tag1:v1/tag2:v2". + update or move a tag value. Example: "tag1:v1/tag1:v2" + or "tag1:v1/tag2:v1" or "tag1:v1/tag2:v2". -r RENAME_EXPRESSION, --rename=RENAME_EXPRESSION rename a tag. Example: "tag1/tag2". -a ADD_EXPRESSION, --add=ADD_EXPRESSION @@ -132,7 +131,7 @@ Options: -d DELETE_EXPRESSION, --delete=DELETE_EXPRESSION delete a tag value or tag. Example: "tag1" or "tag1:v1". - + -s, --show show the extended meta data of the files ``` The *query* option is mandatory. Everything else is optional but there must be at least one additional option. @@ -140,6 +139,17 @@ Except for the *query* option all options are repeatable. By repeating an option #### Examples +##### Show Extended Metadata of matching files + +```shell +beet emd -q title:'404 not found' -s +``` + +With the *show* option the Extended Metadata of each matching file will be printed to the screen. +The Extended Metadata will be shown in its json format. +You can also combine this option with any other options, +in which case the shown Extended Metadata represents the resulting Extended Metadata after all other option have been applied. + ##### Add tags for a specific artist ```shell @@ -203,14 +213,14 @@ by defining different tags and values in both the old- and new tag value express ##### Everything combined ```shell -beet emd -q 'x:origin:germany,austria x:language!german' -a tag:western,lederhosen -a category:good -d circle -u circle:'hyper hyper'/tag:hyper -r category/rating +beet emd -q 'x:origin:germany,austria x:language!german' -a tag:western,lederhosen -a category:good -d circle -u circle:'hyper hyper'/tag:hyper -r category/rating -s ``` This adds the values *western* and *lederhosen* to the tag *tag*, adds *good* to the tag *category*, deletes the tag *circle*, -moves the value *hyper hyper* from tag *circle* to the tag *tag* and changes it to *hyper* -and renames the tag *origin* to country +moves the value *hyper hyper* from tag *circle* to the tag *tag* and changes it to *hyper*, +renames the tag *origin* to country and prints the resulting Extended Metadata to the screen for all songs from *germany* or *austria* that are *not* *german*. Here we delete and rename tags that are also referenced in add and update operations. @@ -219,6 +229,7 @@ In general this works, but it is important to be aware of the order in which the 2. Rename 3. Add 4. Delete +5. Show So in this example we rename *category* to *rating* before we add the value *good* to the tag *category*. So we basically add a tag with the old name after renaming it. diff --git a/beetsplug/emd_command.py b/beetsplug/emd_command.py index 837079f..6ad44f7 100644 --- a/beetsplug/emd_command.py +++ b/beetsplug/emd_command.py @@ -1,13 +1,15 @@ from beets.ui import Subcommand from beetsplug.emd_metadata import ExtendedMetaData -from beetsplug.emd_command_options import EmdAddOption, EmdDeleteOption, EmdUpdateOption, EmdRenameTagOption +from beetsplug.emd_command_options import EmdAddOption, EmdDeleteOption, EmdUpdateOption, EmdRenameTagOption, \ + EmdShowOption emd_command_options = [ EmdUpdateOption(), EmdRenameTagOption(), EmdAddOption(), - EmdDeleteOption() + EmdDeleteOption(), + EmdShowOption() ] @@ -34,10 +36,11 @@ def handle_command(self, lib, opts, _): return query = opts.query - items = lib.items(query) for item in items: + print(item) + old_tags = dict(item).copy() emd = self._get_emd(item) @@ -50,7 +53,6 @@ def handle_command(self, lib, opts, _): if old_tags == new_tags: continue - print(f'Updating meta data for file {item}') item.write() item.store() diff --git a/beetsplug/emd_command_options.py b/beetsplug/emd_command_options.py index 94ff4a2..3e86b36 100644 --- a/beetsplug/emd_command_options.py +++ b/beetsplug/emd_command_options.py @@ -15,10 +15,26 @@ def parser_destination(self): pass @abstractmethod - def apply(self, item, opt_values): + def apply(self, emd, opt_values): pass +class EmdShowOption(EmdCommandOption): + + def apply(self, emd, opt_values): + if opt_values: + print(emd) + + def add_parser_option(self, parser): + parser.add_option( + '-s', '--show', dest=self.parser_destination(), + action="store_true", help='show the extended meta data of the files' + ) + + def parser_destination(self): + return 'show_emd' + + class EmdAddOption(EmdCommandOption): def apply(self, emd, opt_values): diff --git a/beetsplug/emd_metadata.py b/beetsplug/emd_metadata.py index e364616..989b536 100644 --- a/beetsplug/emd_metadata.py +++ b/beetsplug/emd_metadata.py @@ -23,6 +23,9 @@ def __delitem__(self, key): def __contains__(self, key): return key in self._data + def __str__(self): + return str(self._json_data()) + @staticmethod def decode(raw_value): re_result = re.search(ExtendedMetaData._metadata_pattern, str(raw_value)) @@ -48,7 +51,10 @@ def decode(raw_value): return ExtendedMetaData(meta_data) def encode(self): + encoded_data = base64.b64encode(self._json_data().encode('utf-8')).decode('utf-8') + return f'EMD: {encoded_data}' + def _json_data(self): meta_data = self._data.copy() for tag in meta_data.copy(): @@ -59,6 +65,4 @@ def encode(self): elif len(value) == 0: del meta_data[tag] - encoded_data = base64.b64encode(json.dumps(meta_data).encode("utf-8")).decode("utf-8") - - return f'EMD: {encoded_data}' + return json.dumps(meta_data) diff --git a/setup.py b/setup.py index 37e6c76..9e28a89 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ setup( name='beets-extended-metadata', - version='0.2.3', + version='0.2.4', description='beets plugin to use custom, extended metadata', long_description=open('README.md').read(), long_description_content_type='text/markdown', diff --git a/test/test_beets_integration.py b/test/test_beets_integration.py index 66b410e..6e59cc1 100644 --- a/test/test_beets_integration.py +++ b/test/test_beets_integration.py @@ -50,6 +50,11 @@ def _prints_syntax_exception(command_result): return True return False + def test_show_emd(self): + self.beets.command('emd -q title:"Title 1" -a tag1:test1') + self.assertTrue('"tag1": "test1"' in self.beets.command('emd -q title:"Title 1" -s')[1]) + self.assertTrue('"tag1": ["test1", "test2"]' in self.beets.command('emd -q title:"Title 1" -a tag1:test2 -s')[1]) + def test_add_new_tag(self): self.beets.command('emd -q title:"Title 1" -a tag1:test1')