Skip to content

Commit 72c0f69

Browse files
committed
logout command to remove cached credentials
1 parent f615bfa commit 72c0f69

File tree

5 files changed

+80
-5
lines changed

5 files changed

+80
-5
lines changed

src/mopidy_spotify/__init__.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,15 @@ def setup(self, registry):
5050
from mopidy_spotify.backend import SpotifyBackend
5151

5252
registry.add("backend", SpotifyBackend)
53+
54+
def get_command(self):
55+
from .commands import SpotifyCommand
56+
57+
return SpotifyCommand()
58+
59+
@classmethod
60+
def get_credentials_dir(cls, config):
61+
data_dir = cls.get_data_dir(config)
62+
credentials_dir = data_dir / "credentials-cache"
63+
credentials_dir.mkdir(mode=0o700, exist_ok=True)
64+
return credentials_dir

src/mopidy_spotify/backend.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,9 @@ class SpotifyPlaybackProvider(backend.PlaybackProvider):
3737
def __init__(self, *args, **kwargs):
3838
super().__init__(*args, **kwargs)
3939
self._cache_location = Extension().get_cache_dir(self.backend._config)
40-
self._data_location = Extension().get_data_dir(self.backend._config)
40+
self._credentials_dir = Extension().get_credentials_dir(self.backend._config)
4141
self._config = self.backend._config["spotify"]
4242

43-
self._credentials_dir = self._data_location / "credentials-cache"
44-
if not self._credentials_dir.exists():
45-
self._credentials_dir.mkdir(mode=0o700)
46-
4743
def on_source_setup(self, source):
4844
source.set_property("bitrate", str(self._config["bitrate"]))
4945
source.set_property("cache-credentials", self._credentials_dir)

src/mopidy_spotify/commands.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import logging
2+
import os
3+
from pathlib import Path
4+
5+
from mopidy import commands
6+
7+
from mopidy_spotify import Extension
8+
9+
logger = logging.getLogger(__name__)
10+
11+
12+
class SpotifyCommand(commands.Command):
13+
def __init__(self):
14+
super().__init__()
15+
self.add_child("logout", LogoutCommand())
16+
17+
18+
class LogoutCommand(commands.Command):
19+
help = "Logout from Spotify account."
20+
21+
def run(self, _args, config):
22+
credentials_dir = Extension().get_credentials_dir(config)
23+
try:
24+
for root, dirs, files in os.walk(credentials_dir, topdown=False):
25+
root_path = Path(root)
26+
for name in files:
27+
file_path = root_path / name
28+
file_path.unlink()
29+
logger.debug(f"Removed file {file_path}")
30+
for name in dirs:
31+
dir_path = root_path / name
32+
dir_path.rmdir()
33+
logger.debug(f"Removed directory {dir_path}")
34+
credentials_dir.rmdir()
35+
except Exception as error:
36+
logger.warning(f"Failed to logout from Spotify: {error}")
37+
else:
38+
logger.info("Logout from Spotify complete")

tests/test_commands.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
from unittest.mock import sentinel
2+
3+
from mopidy_spotify import Extension
4+
from mopidy_spotify.commands import LogoutCommand
5+
6+
7+
def test_logout_command(tmp_path):
8+
config = {"core": {"data_dir": tmp_path}}
9+
credentials_dir = Extension().get_credentials_dir(config)
10+
(credentials_dir / "foo").mkdir()
11+
(credentials_dir / "bar").touch()
12+
13+
cmd = LogoutCommand()
14+
cmd.run(sentinel.args, config)
15+
16+
assert not credentials_dir.is_dir()

tests/test_extension.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,16 @@ def test_setup():
4040
ext.setup(registry)
4141

4242
registry.add.assert_called_with("backend", backend_lib.SpotifyBackend)
43+
44+
45+
def test_get_credentials_dir(tmp_path):
46+
config = {"core": {"data_dir": tmp_path}}
47+
48+
ext = Extension()
49+
result = ext.get_credentials_dir(config)
50+
assert result == tmp_path / "spotify" / "credentials-cache"
51+
assert result.is_dir()
52+
assert result.stat().st_mode == 0o40700
53+
54+
result2 = ext.get_credentials_dir(config) # check exists_ok
55+
assert result == result2

0 commit comments

Comments
 (0)