From 8a3d8050f972f18c3f008ab272fe1f089dc53faf Mon Sep 17 00:00:00 2001 From: Nick Steel Date: Fri, 11 Oct 2024 01:18:52 +0100 Subject: [PATCH] logout command to remove cached credentials --- src/mopidy_spotify/__init__.py | 12 ++++++++++++ src/mopidy_spotify/backend.py | 6 +----- src/mopidy_spotify/commands.py | 33 +++++++++++++++++++++++++++++++++ tests/test_commands.py | 16 ++++++++++++++++ tests/test_extension.py | 13 +++++++++++++ 5 files changed, 75 insertions(+), 5 deletions(-) create mode 100644 src/mopidy_spotify/commands.py create mode 100644 tests/test_commands.py diff --git a/src/mopidy_spotify/__init__.py b/src/mopidy_spotify/__init__.py index b473fb6d..93b550f7 100644 --- a/src/mopidy_spotify/__init__.py +++ b/src/mopidy_spotify/__init__.py @@ -50,3 +50,15 @@ def setup(self, registry): from mopidy_spotify.backend import SpotifyBackend registry.add("backend", SpotifyBackend) + + def get_command(self): + from .commands import SpotifyCommand + + return SpotifyCommand() + + @classmethod + def get_credentials_dir(cls, config): + data_dir = cls.get_data_dir(config) + credentials_dir = data_dir / "credentials-cache" + credentials_dir.mkdir(mode=0o700, exist_ok=True) + return credentials_dir diff --git a/src/mopidy_spotify/backend.py b/src/mopidy_spotify/backend.py index 5e25a3be..6657c6b6 100644 --- a/src/mopidy_spotify/backend.py +++ b/src/mopidy_spotify/backend.py @@ -37,13 +37,9 @@ class SpotifyPlaybackProvider(backend.PlaybackProvider): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._cache_location = Extension().get_cache_dir(self.backend._config) - self._data_location = Extension().get_data_dir(self.backend._config) + self._credentials_dir = Extension().get_credentials_dir(self.backend._config) self._config = self.backend._config["spotify"] - self._credentials_dir = self._data_location / "credentials-cache" - if not self._credentials_dir.exists(): - self._credentials_dir.mkdir(mode=0o700) - def on_source_setup(self, source): source.set_property("bitrate", str(self._config["bitrate"])) source.set_property("cache-credentials", self._credentials_dir) diff --git a/src/mopidy_spotify/commands.py b/src/mopidy_spotify/commands.py new file mode 100644 index 00000000..4df92c5c --- /dev/null +++ b/src/mopidy_spotify/commands.py @@ -0,0 +1,33 @@ +import logging + +from mopidy import commands + +from mopidy_spotify import Extension + +logger = logging.getLogger(__name__) + + +class SpotifyCommand(commands.Command): + def __init__(self): + super().__init__() + self.add_child("logout", LogoutCommand()) + + +class LogoutCommand(commands.Command): + help = "Logout from Spotify account." + + def run(self, _args, config): + credentials_dir = Extension().get_credentials_dir(config) + try: + for root, dirs, files in credentials_dir.walk(top_down=False): + for name in files: + (root / name).unlink() + logger.debug(f"Removed file {root / name}") + for name in dirs: + (root / name).rmdir() + logger.debug(f"Removed directory {root / name}") + credentials_dir.rmdir() + except Exception as error: + logger.warning(f"Failed to logout from Spotify: {error}") + else: + logger.info("Logout from Spotify complete") diff --git a/tests/test_commands.py b/tests/test_commands.py new file mode 100644 index 00000000..163e4015 --- /dev/null +++ b/tests/test_commands.py @@ -0,0 +1,16 @@ +from unittest.mock import sentinel + +from mopidy_spotify import Extension +from mopidy_spotify.commands import LogoutCommand + + +def test_logout_command(tmp_path): + config = {"core": {"data_dir": tmp_path}} + credentials_dir = Extension().get_credentials_dir(config) + (credentials_dir / "foo").mkdir() + (credentials_dir / "bar").touch() + + cmd = LogoutCommand() + cmd.run(sentinel.args, config) + + assert not credentials_dir.is_dir() diff --git a/tests/test_extension.py b/tests/test_extension.py index efbdddb2..525d3489 100644 --- a/tests/test_extension.py +++ b/tests/test_extension.py @@ -40,3 +40,16 @@ def test_setup(): ext.setup(registry) registry.add.assert_called_with("backend", backend_lib.SpotifyBackend) + + +def test_get_credentials_dir(tmp_path): + config = {"core": {"data_dir": tmp_path}} + + ext = Extension() + result = ext.get_credentials_dir(config) + assert result == tmp_path / "spotify" / "credentials-cache" + assert result.is_dir() + assert result.stat().st_mode == 0o40700 + + result2 = ext.get_credentials_dir(config) # check exists_ok + assert result == result2