Skip to content

Commit

Permalink
feat: error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
krestaino committed Jan 8, 2024
1 parent 5044a11 commit 1396d6d
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 38 deletions.
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.0.0
1.1.0
135 changes: 98 additions & 37 deletions sptnr.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
with open('VERSION', 'r') as file:
with open("VERSION", "r") as file:
__version__ = file.read().strip()

import argparse
Expand Down Expand Up @@ -30,13 +30,42 @@
SPOTIFY_CLIENT_ID = os.getenv("SPOTIFY_CLIENT_ID")
SPOTIFY_CLIENT_SECRET = os.getenv("SPOTIFY_CLIENT_SECRET")

# Colors
LIGHT_PURPLE = Fore.MAGENTA + Style.BRIGHT
LIGHT_GREEN = Fore.GREEN + Style.BRIGHT
LIGHT_RED = Fore.RED + Style.BRIGHT
LIGHT_BLUE = Fore.BLUE + Style.BRIGHT
LIGHT_CYAN = Fore.CYAN + Style.BRIGHT
LIGHT_YELLOW = Fore.YELLOW + Style.BRIGHT
BOLD = Style.BRIGHT
RESET = Style.RESET_ALL

# Setup logs
LOG_DIR = "logs"
if not os.path.exists(LOG_DIR):
os.makedirs(LOG_DIR)

LOGFILE = os.path.join(LOG_DIR, f"spotify-popularity_{int(time.time())}.log")


class NoColorFormatter(logging.Formatter):
ansi_escape = re.compile(r"\x1B\[[0-?]*[ -/]*[@-~]")

def format(self, record):
record.msg = self.ansi_escape.sub("", record.msg)
return super(NoColorFormatter, self).format(record)


# Set up the stream handler (console logging) without timestamp
logging.basicConfig(
level=logging.INFO, format="%(message)s", handlers=[logging.StreamHandler()]
)

# Set up the file handler (file logging) with timestamp
file_handler = logging.FileHandler(LOGFILE, "a")
file_handler.setFormatter(NoColorFormatter("[%(asctime)s] %(message)s"))
logging.getLogger().addHandler(file_handler)

# Auth
HEX_ENCODED_PASS = NAV_PASS.encode().hex()
TOKEN_AUTH = base64.b64encode(
Expand All @@ -48,18 +77,18 @@
headers={"Authorization": f"Basic {TOKEN_AUTH}"},
data={"grant_type": "client_credentials"},
)
SPOTIFY_TOKEN = json.loads(response.text)["access_token"]

init(autoreset=True)
if response.status_code != 200:
error_info = response.json() # Assuming the error response is in JSON format
error_description = error_info.get("error_description", "Unknown error")
logging.error(
f"{LIGHT_RED}Spotify Authentication Error: {error_description}{RESET}"
)
sys.exit(1)

LIGHT_PURPLE = Fore.MAGENTA + Style.BRIGHT
LIGHT_GREEN = Fore.GREEN + Style.BRIGHT
LIGHT_RED = Fore.RED + Style.BRIGHT
LIGHT_BLUE = Fore.BLUE + Style.BRIGHT
LIGHT_CYAN = Fore.CYAN + Style.BRIGHT
LIGHT_YELLOW = Fore.YELLOW + Style.BRIGHT
BOLD = Style.BRIGHT
RESET = Style.RESET_ALL
SPOTIFY_TOKEN = response.json()["access_token"]

init(autoreset=True)

# Default flags
PREVIEW = 0
Expand All @@ -75,26 +104,6 @@
NOT_FOUND = 0
UNMATCHED_TRACKS = []


# Setup logging
class NoColorFormatter(logging.Formatter):
ansi_escape = re.compile(r"\x1B\[[0-?]*[ -/]*[@-~]")

def format(self, record):
record.msg = self.ansi_escape.sub("", record.msg)
return super(NoColorFormatter, self).format(record)


# Set up the stream handler (console logging) without timestamp
logging.basicConfig(
level=logging.INFO, format="%(message)s", handlers=[logging.StreamHandler()]
)

# Set up the file handler (file logging) with timestamp
file_handler = logging.FileHandler(LOGFILE, "a")
file_handler.setFormatter(NoColorFormatter("[%(asctime)s] %(message)s"))
logging.getLogger().addHandler(file_handler)

# Parse arguments
description_text = "process command-line flags for sync"
parser = argparse.ArgumentParser()
Expand Down Expand Up @@ -159,6 +168,20 @@ def format(self, record):
)


def validate_url(url):
if not re.match(r"https?://", url):
logging.error(
f"{LIGHT_RED}Config Error: URL must start with 'http://' or 'https://'.{RESET}"
)
return False
if url.endswith("/"):
logging.error(
f"{LIGHT_RED}Config Error: URL must not end with a trailing slash.{RESET}"
)
return False
return True


def url_encode(string):
return urllib.parse.quote_plus(string)

Expand Down Expand Up @@ -187,24 +210,24 @@ def search_spotify(query):
try:
response = requests.get(spotify_url, headers=headers)
except requests.exceptions.ConnectionError:
logging.error(f"{LIGHT_RED}Error: Unable to reach server.{RESET}")
logging.error(f"{LIGHT_RED}Spotify Error: Unable to reach server.{RESET}")
sys.exit(1)

if response.status_code != 200:
if response.status_code == 429:
logging.error(
f"{LIGHT_RED}Error {response.status_code}: Retry after {BOLD}{response.headers.get('Retry-After', 'some time')}s{RESET}"
f"{LIGHT_RED}Spotify Error {response.status_code}: Retry after {BOLD}{response.headers.get('Retry-After', 'some time')}s{RESET}"
)
else:
logging.error(
f"{LIGHT_RED}Error {response.status_code}: {response.text}{RESET}"
f"{LIGHT_RED}Spotify Error {response.status_code}: {response.text}{RESET}"
)
sys.exit(1)
try:
return response.json()
except ValueError as e:
logging.error(
f"{LIGHT_RED}Error decoding JSON from Spotify API: {e}{RESET}"
f"{LIGHT_RED}Spotify Error: Error decoding JSON from Spotify API: {e}{RESET}"
)
sys.exit(1)

Expand Down Expand Up @@ -285,9 +308,47 @@ def process_artist(artist_id):


def fetch_data(url):
response = requests.get(url)
return json.loads(response.text)["subsonic-response"]
try:
response = requests.get(url)
response_data = json.loads(response.text)

if "subsonic-response" not in response_data:
logging.error(
f"{LIGHT_RED}Unexpected response format from Navidrome.{RESET}"
)
sys.exit(1)

nav_response = response_data["subsonic-response"]

if "error" in nav_response:
error_message = nav_response["error"].get("message", "Unknown error")
logging.error(f"{LIGHT_RED}Navidrome Error: {error_message}{RESET}")
sys.exit(1)

return nav_response

except requests.exceptions.ConnectionError:
logging.error(
f"{LIGHT_RED}Connection Error: Failed to connect to the provided URL. Please check if the URL is correct and the server is reachable.{RESET}"
)
sys.exit(1)
except requests.exceptions.RequestException as e:
logging.error(
f"{LIGHT_RED}Connection Error: An error occurred while trying to connect to Navidrome: {e}{RESET}"
)
sys.exit(1)
except json.JSONDecodeError:
logging.error(
f"{LIGHT_RED}JSON Parsing Error: Failed to parse JSON response from Navidrome. Please check if the provided URL is a valid Navidrome server.{RESET}"
)
sys.exit(1)


try:
validate_url(NAV_BASE_URL)
except ValueError as e:
logging.error(f"{LIGHT_RED}{e}{RESET}")
sys.exit(1)

if ARTIST_IDs:
for ARTIST_ID in ARTIST_IDs:
Expand Down

0 comments on commit 1396d6d

Please sign in to comment.