streamrip/rip/config.py

164 lines
4.9 KiB
Python
Raw Normal View History

"""A config class that manages arguments between the config file and CLI."""
2021-05-07 01:03:55 -04:00
import copy
2021-03-22 12:21:27 -04:00
import logging
import os
import shutil
2021-04-14 21:31:24 -04:00
from pprint import pformat
from typing import Any, Dict
2021-03-22 12:21:27 -04:00
import tomlkit
2021-07-30 14:39:51 -04:00
from click import secho
2021-03-22 12:21:27 -04:00
from streamrip.exceptions import InvalidSourceError
2021-03-22 12:21:27 -04:00
2021-07-29 01:29:30 -04:00
from .constants import CONFIG_DIR, CONFIG_PATH, DOWNLOADS_DIR
2021-05-12 18:19:51 -04:00
logger = logging.getLogger("streamrip")
2021-03-22 12:21:27 -04:00
class Config:
"""Config class that handles command line args and config files.
Usage:
>>> config = Config('test_config.toml')
>>> config.defaults['qobuz']['quality']
3
2021-03-22 12:21:27 -04:00
If test_config was already initialized with values, this will load them
into `config`. Otherwise, a new config file is created with the default
values.
"""
default_config_path = os.path.join(os.path.dirname(__file__), "config.toml")
with open(default_config_path) as cfg:
defaults: Dict[str, Any] = tomlkit.parse(cfg.read().strip())
def __init__(self, path: str = None):
2021-05-04 15:57:00 -04:00
"""Create a Config object with state.
A TOML file is created at `path` if there is none.
2021-05-04 15:57:00 -04:00
:param path:
:type path: str
"""
# to access settings loaded from toml file
2021-04-28 03:24:17 -04:00
self.file: Dict[str, Any] = copy.deepcopy(self.defaults)
self.session: Dict[str, Any] = copy.deepcopy(self.defaults)
2021-03-22 12:21:27 -04:00
if path is None:
self._path = CONFIG_PATH
else:
self._path = path
if os.path.isfile(self._path):
self.load()
if self.file["misc"]["version"] != self.defaults["misc"]["version"]:
secho(
"Updating config file to new version. Some settings may be lost.",
fg="yellow",
)
self.update()
self.load()
else:
logger.debug("Creating toml config file at '%s'", self._path)
2021-07-31 12:28:07 -04:00
os.makedirs(os.path.dirname(self._path), exist_ok=True)
shutil.copy(self.default_config_path, self._path)
self.load()
self.file["downloads"]["folder"] = DOWNLOADS_DIR
2021-03-22 12:21:27 -04:00
2021-04-16 17:24:59 -04:00
def update(self):
2021-05-04 15:57:00 -04:00
"""Reset the config file except for credentials."""
2021-04-16 17:24:59 -04:00
self.reset()
# Save original credentials
qobuz_creds = self.file["qobuz"]
tidal_creds = self.file["tidal"]
# Reset and load config file
shutil.copy(self.default_config_path, self._path)
self.load()
# Set credentials and download directory, then save
self.file["qobuz"].update(qobuz_creds)
self.file["tidal"].update(tidal_creds)
self.file["downloads"]["folder"] = DOWNLOADS_DIR
self.save()
2021-04-16 17:24:59 -04:00
def save(self):
2021-04-10 19:05:31 -04:00
"""Save the config state to file."""
self.dump(self.file)
2021-03-22 12:21:27 -04:00
def reset(self):
2021-04-10 19:05:31 -04:00
"""Reset the config file."""
if not os.path.isdir(CONFIG_DIR):
os.makedirs(CONFIG_DIR, exist_ok=True)
shutil.copy(self.default_config_path, self._path)
self.load()
self.file["downloads"]["folder"] = DOWNLOADS_DIR
self.save()
2021-03-22 12:21:27 -04:00
def load(self):
2021-04-10 19:05:31 -04:00
"""Load infomation from the config files, making a deepcopy."""
2021-03-22 12:21:27 -04:00
with open(self._path) as cfg:
for k, v in tomlkit.loads(cfg.read().strip()).items():
self.file[k] = v
if hasattr(v, "copy"):
self.session[k] = v.copy()
else:
self.session[k] = v
2021-03-22 12:21:27 -04:00
logger.debug("Config loaded")
self.__loaded = True
def dump(self, info):
2021-04-10 19:05:31 -04:00
"""Given a state of the config, save it to the file.
:param info:
"""
2021-03-22 12:21:27 -04:00
with open(self._path, "w") as cfg:
logger.debug("Config saved: %s", self._path)
cfg.write(tomlkit.dumps(info))
2021-04-14 21:30:27 -04:00
2021-03-22 12:21:27 -04:00
@property
def tidal_creds(self):
2021-04-10 19:05:31 -04:00
"""Return a TidalClient compatible dict of credentials."""
2021-03-29 18:46:26 -04:00
creds = dict(self.file["tidal"])
2021-03-29 15:12:50 -04:00
logger.debug(creds)
2021-03-29 18:46:26 -04:00
del creds["quality"] # should not be included in creds
2021-04-19 16:41:40 -04:00
del creds["download_videos"]
2021-03-29 15:12:50 -04:00
return creds
2021-03-22 12:21:27 -04:00
@property
def qobuz_creds(self):
2021-04-10 19:05:31 -04:00
"""Return a QobuzClient compatible dict of credentials."""
2021-03-22 12:21:27 -04:00
return {
"email": self.file["qobuz"]["email"],
"pwd": self.file["qobuz"]["password"],
"app_id": self.file["qobuz"]["app_id"],
"secrets": self.file["qobuz"]["secrets"],
2021-03-22 12:21:27 -04:00
}
def creds(self, source: str):
2021-04-10 19:05:31 -04:00
"""Return a Client compatible dict of credentials.
:param source:
:type source: str
"""
2021-03-22 12:21:27 -04:00
if source == "qobuz":
return self.qobuz_creds
2021-04-10 19:05:31 -04:00
if source == "tidal":
2021-03-22 12:21:27 -04:00
return self.tidal_creds
2021-07-28 17:26:14 -04:00
if source == "deezer":
return {"arl": self.file["deezer"]["arl"]}
if source == "soundcloud":
return {}
2021-04-10 19:05:31 -04:00
raise InvalidSourceError(source)
2021-03-22 12:21:27 -04:00
def __repr__(self):
2021-05-04 15:57:00 -04:00
"""Return a string representation of the config."""
return f"Config({pformat(self.session)})"