-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: new sync plugin to sync music metadata
- Loading branch information
Showing
10 changed files
with
346 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,4 +19,5 @@ These are all the plugins that are enabled by default. | |
move | ||
musicbrainz | ||
remove | ||
sync | ||
write |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
#### | ||
Sync | ||
#### | ||
Syncs music metadata from connected sources. | ||
|
||
************* | ||
Configuration | ||
************* | ||
The ``sync`` plugin is enabled by default. | ||
|
||
*********** | ||
Commandline | ||
*********** | ||
.. code-block:: bash | ||
moe sync [-h] [-a | -e] [-p] query | ||
Options | ||
======= | ||
``-h, --help`` | ||
Display the help message. | ||
``-a, --album`` | ||
Query for matching albums instead of tracks. | ||
``-e, --extra`` | ||
Query for matching extras instead of tracks. | ||
|
||
Arguments | ||
========= | ||
``query`` | ||
Query your library for items to sync. See the :doc:`query docs <../query>` for more info. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -45,6 +45,7 @@ | |
"list", | ||
"move", | ||
"musicbrainz", | ||
"sync", | ||
"remove", | ||
"write", | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
"""Syncs library metadata with external sources.""" | ||
|
||
import moe | ||
from moe import config | ||
|
||
from . import sync_cli, sync_core | ||
from .sync_core import * | ||
|
||
__all__ = [] | ||
__all__.extend(sync_core.__all__) | ||
|
||
|
||
@moe.hookimpl | ||
def plugin_registration(): | ||
"""Only register the cli sub-plugin if the cli is enabled.""" | ||
config.CONFIG.pm.register(sync_core, "sync_core") | ||
if config.CONFIG.pm.has_plugin("cli"): | ||
config.CONFIG.pm.register(sync_cli, "sync_cli") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
"""Adds the ``sync`` command to sync library metadata.""" | ||
|
||
import argparse | ||
import logging | ||
|
||
import moe | ||
import moe.cli | ||
from moe.plugins import sync as moe_sync | ||
from moe.query import QueryError, query | ||
|
||
log = logging.getLogger("moe.cli.sync") | ||
|
||
__all__: list[str] = [] | ||
|
||
|
||
@moe.hookimpl | ||
def add_command(cmd_parsers: argparse._SubParsersAction): | ||
"""Adds the ``add`` command to Moe's CLI.""" | ||
add_parser = cmd_parsers.add_parser( | ||
"sync", | ||
description="Sync music metadata.", | ||
help="sync music metadata", | ||
parents=[moe.cli.query_parser], | ||
) | ||
add_parser.set_defaults(func=_parse_args) | ||
|
||
|
||
def _parse_args(args: argparse.Namespace): | ||
"""Parses the given commandline arguments. | ||
Args: | ||
args: Commandline arguments to parse. | ||
Raises: | ||
SystemExit: Invalid query given or query returned no items. | ||
""" | ||
try: | ||
items = query(args.query, query_type=args.query_type) | ||
except QueryError as err: | ||
log.error(err) | ||
raise SystemExit(1) from err | ||
|
||
if not items: | ||
log.error("No items found to sync.") | ||
raise SystemExit(1) | ||
|
||
for item in items: | ||
moe_sync.sync_item(item) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
"""Sync metadata from external sources.""" | ||
|
||
import logging | ||
|
||
import moe | ||
from moe import config | ||
from moe.library import LibItem | ||
|
||
log = logging.getLogger("moe.sync") | ||
|
||
__all__ = ["sync_item"] | ||
|
||
|
||
class Hooks: | ||
"""Sync plugin hook specifications.""" | ||
|
||
@staticmethod | ||
@moe.hookspec | ||
def sync_metadata(item: LibItem): | ||
"""Implement specific metadata syncing for ``item``.""" | ||
|
||
|
||
def sync_item(item: LibItem): | ||
"""Syncs metadata from external sources and merges changes into ``item``.""" | ||
log.debug(f"Syncing metadata. [{item=!r}]") | ||
|
||
config.CONFIG.pm.hook.sync_metadata(item) | ||
|
||
log.debug(f"Synced metadata. [{item=!r}]") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
"""Test sync plugin cli.""" | ||
|
||
from unittest.mock import call, patch | ||
|
||
import pytest | ||
|
||
import moe | ||
import moe.cli | ||
from moe.query import QueryError | ||
from tests.conftest import track_factory | ||
|
||
|
||
@pytest.fixture | ||
def mock_sync(): | ||
"""Mock the `sync_item()` api call.""" | ||
with patch( | ||
"moe.plugins.sync.sync_cli.moe_sync.sync_item", autospec=True | ||
) as mock_sync: | ||
yield mock_sync | ||
|
||
|
||
@pytest.fixture | ||
def mock_query(): | ||
"""Mock a database query call. | ||
Use ``mock_query.return_value` to set the return value of a query. | ||
Yields: | ||
Mock query | ||
""" | ||
with patch("moe.plugins.sync.sync_cli.query", autospec=True) as mock_query: | ||
yield mock_query | ||
|
||
|
||
@pytest.fixture | ||
def _tmp_sync_config(tmp_config): | ||
"""A temporary config for the list plugin with the cli.""" | ||
tmp_config('default_plugins = ["cli", "sync"]') | ||
|
||
|
||
@pytest.mark.usefixtures("_tmp_sync_config") | ||
class TestCommand: | ||
"""Test the `sync` command.""" | ||
|
||
def test_items(self, mock_query, mock_sync): | ||
"""Tracks are synced with a valid query.""" | ||
track1 = track_factory() | ||
track2 = track_factory() | ||
cli_args = ["sync", "*"] | ||
mock_query.return_value = [track1, track2] | ||
|
||
moe.cli.main(cli_args) | ||
|
||
mock_query.assert_called_once_with("*", query_type="track") | ||
mock_sync.assert_has_calls([call(track1), call(track2)]) | ||
|
||
def test_exit_code(self, mock_query, mock_sync): | ||
"""Return a non-zero exit code if no items are returned from the query.""" | ||
cli_args = ["sync", "*"] | ||
mock_query.return_value = [] | ||
|
||
with pytest.raises(SystemExit) as error: | ||
moe.cli.main(cli_args) | ||
|
||
assert error.value.code != 0 | ||
mock_sync.assert_not_called() | ||
|
||
def test_bad_query(self, mock_query): | ||
"""Raise SystemExit if given a bad query.""" | ||
cli_args = ["sync", "*"] | ||
mock_query.side_effect = QueryError | ||
|
||
with pytest.raises(SystemExit) as error: | ||
moe.cli.main(cli_args) | ||
|
||
assert error.value.code != 0 |
Oops, something went wrong.