Chrunos commited on
Commit
262a6f1
·
verified ·
1 Parent(s): f633005

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +57 -12
app.py CHANGED
@@ -1,12 +1,11 @@
1
  import base64
2
  import logging
3
- from typing import Optional
4
- from functools import lru_cache
5
  from fastapi import FastAPI, HTTPException, Request
6
  import requests
7
  from bs4 import BeautifulSoup
8
  import os
9
- from datetime import datetime
10
  import time
11
 
12
  # Configure logging
@@ -27,16 +26,44 @@ app = FastAPI(title="Spotify Track API",
27
  SPOTIFY_API_URL = "https://api.spotify.com/v1"
28
  SPOTIFY_CLIENT_ID = os.getenv("SPOTIFY_CLIENT_ID")
29
  SPOTIFY_CLIENT_SECRET = os.getenv("SPOTIFY_CLIENT_SECRET")
30
- TOKEN_EXPIRY = 3600 # Spotify token expires in 1 hour
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
 
32
  # Custom exception for Spotify API errors
33
  class SpotifyAPIError(Exception):
34
  pass
35
 
36
- # Cache token for 1 hour
37
- @lru_cache(maxsize=1)
38
- def get_spotify_token():
 
 
39
  try:
 
 
 
 
 
 
40
  logger.info("Requesting new Spotify access token")
41
  start_time = time.time()
42
 
@@ -56,9 +83,11 @@ def get_spotify_token():
56
  if auth_response.status_code != 200:
57
  raise SpotifyAPIError(f"Failed to get token: {auth_response.text}")
58
 
59
- token = auth_response.json()['access_token']
60
- logger.info(f"Token obtained successfully in {time.time() - start_time:.2f}s")
61
- return token
 
 
62
 
63
  except requests.exceptions.RequestException as e:
64
  logger.error(f"Network error during token request: {str(e)}")
@@ -85,7 +114,7 @@ async def get_track_download_url(track_id: str) -> str:
85
  for api_url in apis:
86
  try:
87
  logger.info(f"Attempting to get download URL from: {api_url}")
88
- response = requests.get(api_url, timeout=20)
89
  if response.status_code == 200:
90
  download_url = response.json().get("url")
91
  if download_url:
@@ -133,6 +162,18 @@ async def get_track(
133
  timeout=10
134
  )
135
 
 
 
 
 
 
 
 
 
 
 
 
 
136
  if response.status_code != 200:
137
  logger.error(f"Request {request_id} - Spotify API error: {response.text}")
138
  raise HTTPException(
@@ -171,7 +212,11 @@ async def health_check():
171
  try:
172
  # Test Spotify API token generation
173
  token = get_spotify_token()
174
- return {"status": "healthy", "spotify_auth": "ok"}
 
 
 
 
175
  except Exception as e:
176
  logger.error(f"Health check failed: {str(e)}")
177
  return {"status": "unhealthy", "error": str(e)}
 
1
  import base64
2
  import logging
3
+ from typing import Optional, Dict
 
4
  from fastapi import FastAPI, HTTPException, Request
5
  import requests
6
  from bs4 import BeautifulSoup
7
  import os
8
+ from datetime import datetime, timedelta
9
  import time
10
 
11
  # Configure logging
 
26
  SPOTIFY_API_URL = "https://api.spotify.com/v1"
27
  SPOTIFY_CLIENT_ID = os.getenv("SPOTIFY_CLIENT_ID")
28
  SPOTIFY_CLIENT_SECRET = os.getenv("SPOTIFY_CLIENT_SECRET")
29
+ TOKEN_EXPIRY = 3500 # Slightly less than 1 hour to ensure token refresh before expiration
30
+
31
+ # Token cache
32
+ class TokenCache:
33
+ def __init__(self):
34
+ self.token: Optional[str] = None
35
+ self.expiry_time: Optional[datetime] = None
36
+
37
+ def set_token(self, token: str):
38
+ self.token = token
39
+ self.expiry_time = datetime.now() + timedelta(seconds=TOKEN_EXPIRY)
40
+
41
+ def get_token(self) -> Optional[str]:
42
+ if not self.token or not self.expiry_time or datetime.now() >= self.expiry_time:
43
+ return None
44
+ return self.token
45
+
46
+ def is_expired(self) -> bool:
47
+ return not self.token or not self.expiry_time or datetime.now() >= self.expiry_time
48
+
49
+ token_cache = TokenCache()
50
 
51
  # Custom exception for Spotify API errors
52
  class SpotifyAPIError(Exception):
53
  pass
54
 
55
+ def get_spotify_token() -> str:
56
+ """
57
+ Get Spotify access token with expiration handling.
58
+ Returns a valid token, either from cache or by requesting a new one.
59
+ """
60
  try:
61
+ # Check if we have a valid cached token
62
+ cached_token = token_cache.get_token()
63
+ if cached_token:
64
+ logger.info("Using cached Spotify token")
65
+ return cached_token
66
+
67
  logger.info("Requesting new Spotify access token")
68
  start_time = time.time()
69
 
 
83
  if auth_response.status_code != 200:
84
  raise SpotifyAPIError(f"Failed to get token: {auth_response.text}")
85
 
86
+ new_token = auth_response.json()['access_token']
87
+ token_cache.set_token(new_token)
88
+
89
+ logger.info(f"New token obtained successfully in {time.time() - start_time:.2f}s")
90
+ return new_token
91
 
92
  except requests.exceptions.RequestException as e:
93
  logger.error(f"Network error during token request: {str(e)}")
 
114
  for api_url in apis:
115
  try:
116
  logger.info(f"Attempting to get download URL from: {api_url}")
117
+ response = requests.get(api_url, timeout=10)
118
  if response.status_code == 200:
119
  download_url = response.json().get("url")
120
  if download_url:
 
162
  timeout=10
163
  )
164
 
165
+ # Handle token expiration
166
+ if response.status_code == 401:
167
+ logger.info("Token expired, requesting new token")
168
+ token_cache.token = None # Clear expired token
169
+ access_token = get_spotify_token()
170
+ # Retry the request with new token
171
+ response = requests.get(
172
+ f"{SPOTIFY_API_URL}/tracks/{track_id}",
173
+ headers={"Authorization": f"Bearer {access_token}"},
174
+ timeout=10
175
+ )
176
+
177
  if response.status_code != 200:
178
  logger.error(f"Request {request_id} - Spotify API error: {response.text}")
179
  raise HTTPException(
 
212
  try:
213
  # Test Spotify API token generation
214
  token = get_spotify_token()
215
+ return {
216
+ "status": "healthy",
217
+ "spotify_auth": "ok",
218
+ "token_expires_in": token_cache.expiry_time.timestamp() - datetime.now().timestamp() if token_cache.expiry_time else None
219
+ }
220
  except Exception as e:
221
  logger.error(f"Health check failed: {str(e)}")
222
  return {"status": "unhealthy", "error": str(e)}