Skip to content

Commit

Permalink
rework spotipy cache and settings.ini storage
Browse files Browse the repository at this point in the history
  • Loading branch information
sigma67 committed Aug 20, 2023
1 parent a07611b commit 6a52100
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 31 deletions.
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ classifiers = [
]
dependencies = [
"ytmusicapi>=1.0",
"spotipy>=2.23.0"
"spotipy>=2.23.0",
"platformdirs>=2.0"
]
dynamic = ["version", "readme"]

Expand Down
23 changes: 19 additions & 4 deletions spotify_to_ytmusic/settings.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,35 @@
import configparser
import shutil
import warnings
from pathlib import Path
from typing import Optional

import platformdirs

CACHE_DIR = Path(
platformdirs.user_cache_dir(appname="spotify_to_ytmusic", appauthor=False, ensure_exists=True)
)
DEFAULT_PATH = CACHE_DIR.joinpath("settings.ini")
EXAMPLE_PATH = Path(__file__).parent.joinpath("settings.ini.example")


class Settings:
config: configparser.ConfigParser
filepath: Path = Path(__file__).parent.joinpath("settings.ini")
filepath: Path = DEFAULT_PATH

def __init__(self, filepath: Optional[Path] = None):
self.config = configparser.ConfigParser(interpolation=None)
if filepath:
self.filepath = filepath
if not self.filepath.is_file():
raise FileNotFoundError(
f"No settings.ini not found! Please run \n\n spotify_to_ytmusic setup"
)
try:
# Migration path for pre 0.3.0
shutil.copy(EXAMPLE_PATH.with_suffix(""), DEFAULT_PATH)
warnings.warn(f"Moved {filepath} to {DEFAULT_PATH}", DeprecationWarning)
except Exception as exc:
raise FileNotFoundError(
f"No settings.ini found! Please run \n\n spotify_to_ytmusic setup"
)
self.config.read(self.filepath)

def __getitem__(self, key):
Expand Down
14 changes: 4 additions & 10 deletions spotify_to_ytmusic/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@

import ytmusicapi

from spotify_to_ytmusic.settings import Settings
from spotify_to_ytmusic.settings import DEFAULT_PATH, EXAMPLE_PATH, Settings


def setup(file: Optional[Path] = None):
if file:
setup_file(file)
shutil.copy(file, DEFAULT_PATH)
return

if not Settings.filepath.is_file():
shutil.copy(Settings.filepath.with_suffix(".ini.example"), Settings.filepath)
if not DEFAULT_PATH.is_file():
shutil.copy(EXAMPLE_PATH, DEFAULT_PATH)
choice = input("Choose which API to set up\n" "(1) Spotify\n" "(2) YouTube\n" "(3) both\n")
choices = ["1", "2", "3"]
if choice not in choices:
Expand Down Expand Up @@ -47,9 +47,3 @@ def setup_spotify():
}
settings["spotify"].update(credentials)
settings.save()


def setup_file(file: Path):
if not file:
raise FileNotFoundError(f"{file} not found")
shutil.copy(file, Settings.filepath)
8 changes: 6 additions & 2 deletions spotify_to_ytmusic/spotify.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
from urllib.parse import urlparse

import spotipy
from spotipy import CacheFileHandler
from spotipy.oauth2 import SpotifyClientCredentials, SpotifyOAuth

from spotify_to_ytmusic.settings import Settings
from spotify_to_ytmusic.settings import CACHE_DIR, Settings


class Spotify:
Expand All @@ -23,17 +24,20 @@ def __init__(self):
), f"Spotify client_secret not set or invalid: {client_secret}"

use_oauth = conf.getboolean("use_oauth")

cache_handler = CacheFileHandler(cache_path=CACHE_DIR.joinpath("spotipy.cache").as_posix())
if use_oauth:
auth = SpotifyOAuth(
client_id=client_id,
client_secret=client_secret,
redirect_uri="http://localhost",
scope="user-library-read",
cache_handler=cache_handler,
)
self.api = spotipy.Spotify(auth_manager=auth)
else:
client_credentials_manager = SpotifyClientCredentials(
client_id=client_id, client_secret=client_secret
client_id=client_id, client_secret=client_secret, cache_handler=cache_handler
)
self.api = spotipy.Spotify(client_credentials_manager=client_credentials_manager)

Expand Down
37 changes: 23 additions & 14 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
import json
import shutil
import time
import unittest
from io import StringIO
from pathlib import Path
from unittest import mock

from spotify_to_ytmusic import settings as settings_module
from spotify_to_ytmusic import setup
from spotify_to_ytmusic.main import get_args, main
from spotify_to_ytmusic.settings import Settings
from spotify_to_ytmusic.settings import DEFAULT_PATH, EXAMPLE_PATH, Settings

TEST_PLAYLIST = "https://open.spotify.com/playlist/4UzyZJfSQ4584FaWGwepfL"


class TestCli(unittest.TestCase):
@classmethod
def setUpClass(cls):
Settings()

def test_get_args(self):
args = get_args(["all", "user"])
self.assertEqual(len(vars(args)), 3)
Expand Down Expand Up @@ -53,24 +57,29 @@ def test_create(self):
) # assert number of lines deleted

def test_setup(self):
tmp_path = Path(__file__).parent.joinpath("settings.tmp")
example_path = Settings.filepath.parent.joinpath("settings.ini.example")
shutil.copy(example_path, tmp_path)
with mock.patch("sys.argv", ["", "setup"]), mock.patch(
"builtins.input", side_effect=["3", "a", "b", "yes", ""]
), mock.patch(
"ytmusicapi.auth.oauth.YTMusicOAuth.get_token_from_code",
return_value=json.loads(Settings()["youtube"]["headers"]),
tmp_path = DEFAULT_PATH.with_suffix(".tmp")
with (
mock.patch("sys.argv", ["", "setup"]),
mock.patch("builtins.input", side_effect=["3", "a", "b", "yes", ""]),
mock.patch(
"ytmusicapi.auth.oauth.YTMusicOAuth.get_token_from_code",
return_value=json.loads(Settings()["youtube"]["headers"]),
),
mock.patch.object(setup, "DEFAULT_PATH", tmp_path),
mock.patch.object(settings_module, "DEFAULT_PATH", tmp_path),
mock.patch.object(Settings, "filepath", tmp_path),
):
main()
assert tmp_path.is_file()
settings = Settings()
settings = Settings() # reload settings
assert settings["spotify"]["client_id"] == "a"
assert settings["spotify"]["client_secret"] == "b"
tmp_path.unlink()

with mock.patch("sys.argv", ["", "setup", "--file", example_path.as_posix()]), mock.patch(
"spotify_to_ytmusic.settings.Settings.filepath", tmp_path
with (
mock.patch("sys.argv", ["", "setup", "--file", EXAMPLE_PATH.as_posix()]),
mock.patch.object(setup, "DEFAULT_PATH", tmp_path),
mock.patch.object(settings_module, "DEFAULT_PATH", tmp_path),
):
main()
assert tmp_path.is_file()
Expand Down

0 comments on commit 6a52100

Please sign in to comment.