refactor: Make rate limiting configurable and move session validation to Tidal class

- Add api_rate_limit_batch_size and api_rate_limit_delay_sec to Settings (cfg.py)
- Move validate_session() and is_authentication_error() to Tidal class (config.py)
- Update _load_albums_with_rate_limiting() to use config values instead of hardcoded 20/3
- Update _handle_album_load_error() to use Tidal.is_authentication_error()
- Remove _validate_session() from gui.py (now uses Tidal.validate_session())
- Addresses maintainer feedback: configurable tweaking variables and proper separation of concerns
This commit is contained in:
Winman486
2025-10-21 15:23:18 -05:00
parent 6c1704e3c4
commit e9070eef66
3 changed files with 37 additions and 21 deletions
+20
View File
@@ -190,6 +190,26 @@ class Tidal(BaseConfig, metaclass=SingletonMeta):
return True return True
def validate_session(self) -> bool:
"""Validate that the TIDAL session is still authenticated.
Returns:
bool: True if session is valid, False otherwise.
"""
return self.session.check_login()
def is_authentication_error(self, error: Exception) -> bool:
"""Check if an error is related to authentication/OAuth issues.
Args:
error (Exception): The exception to check.
Returns:
bool: True if the error is authentication-related, False otherwise.
"""
error_msg = str(error)
return "401" in error_msg or "OAuth" in error_msg or "token" in error_msg.lower()
class HandlingApp(metaclass=SingletonMeta): class HandlingApp(metaclass=SingletonMeta):
event_abort: Event = Event() event_abort: Event = Event()
+11 -20
View File
@@ -728,16 +728,19 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
dict[int, Album]: Dictionary of successfully loaded full album objects. dict[int, Album]: Dictionary of successfully loaded full album objects.
""" """
albums_dict = {} albums_dict = {}
batch_size = self.settings.data.api_rate_limit_batch_size
delay_sec = self.settings.data.api_rate_limit_delay_sec
for idx, album_id in enumerate(album_ids.keys(), start=1): for idx, album_id in enumerate(album_ids.keys(), start=1):
try: try:
# Add delay every 20 albums to avoid rate limiting # Add delay every N albums to avoid rate limiting
if idx > 1 and (idx - 1) % 20 == 0: if idx > 1 and (idx - 1) % batch_size == 0:
logger_gui.info(f"🛑 RATE LIMITING: Processed {idx - 1} albums, pausing for 3 seconds...") logger_gui.info(f"🛑 RATE LIMITING: Processed {idx - 1} albums, pausing for {delay_sec} seconds...")
time.sleep(3) time.sleep(delay_sec)
# Check session validity before making API calls # Check session validity before making API calls
if not self._validate_session(): if not self.tidal.validate_session():
logger_gui.error("Session expired. Please restart the application and login again.")
return albums_dict return albums_dict
# Reload full album object # Reload full album object
@@ -753,17 +756,6 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
logger_gui.info(f"Successfully loaded {len(albums_dict)} albums.") logger_gui.info(f"Successfully loaded {len(albums_dict)} albums.")
return albums_dict return albums_dict
def _validate_session(self) -> bool:
"""Validate that the TIDAL session is still authenticated.
Returns:
bool: True if session is valid, False otherwise.
"""
if not self.tidal.session.check_login():
logger_gui.error("Session expired. Please restart the application and login again.")
return False
return True
def _handle_album_load_error(self, error: Exception, album_id: int) -> bool: def _handle_album_load_error(self, error: Exception, album_id: int) -> bool:
"""Handle errors that occur when loading an album. """Handle errors that occur when loading an album.
@@ -774,10 +766,9 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
Returns: Returns:
bool: True if processing should continue, False if it should stop. bool: True if processing should continue, False if it should stop.
""" """
# Check for OAuth/authentication errors using Tidal class method
if self.tidal.is_authentication_error(error):
error_msg = str(error) error_msg = str(error)
# Check for OAuth/authentication errors
if "401" in error_msg or "OAuth" in error_msg or "token" in error_msg.lower():
logger_gui.error(f"Authentication error: {error_msg}") logger_gui.error(f"Authentication error: {error_msg}")
logger_gui.error("Your session has expired. Please restart the application and login again.") logger_gui.error("Your session has expired. Please restart the application and login again.")
self.s_statusbar_message.emit( self.s_statusbar_message.emit(
@@ -785,7 +776,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
) )
return False return False
logger_gui.warning(f"Failed to load album {album_id}: {error_msg}") logger_gui.warning(f"Failed to load album {album_id}: {error!s}")
logger_gui.info( logger_gui.info(
"Note: Some albums may be unavailable due to region restrictions or removal from TIDAL. This is normal." "Note: Some albums may be unavailable due to region restrictions or removal from TIDAL. This is normal."
) )
+5
View File
@@ -59,6 +59,9 @@ class Settings:
filename_delimiter_artist: str = ", " filename_delimiter_artist: str = ", "
filename_delimiter_album_artist: str = ", " filename_delimiter_album_artist: str = ", "
metadata_target_upc: MetadataTargetUPC = MetadataTargetUPC.UPC metadata_target_upc: MetadataTargetUPC = MetadataTargetUPC.UPC
# Rate limiting for API calls (tweaking variables)
api_rate_limit_batch_size: int = 20 # Number of albums to process before applying rate limit delay
api_rate_limit_delay_sec: float = 3.0 # Delay in seconds between batches to avoid rate limiting
@dataclass_json @dataclass_json
@@ -127,6 +130,8 @@ class HelpSettings:
metadata_target_upc: str = ( metadata_target_upc: str = (
"Select the target metadata tag ('UPC', 'BARCODE', 'EAN') where to write the UPC information to. Default: 'UPC'." "Select the target metadata tag ('UPC', 'BARCODE', 'EAN') where to write the UPC information to. Default: 'UPC'."
) )
api_rate_limit_batch_size: str = "Number of albums to process before applying rate limit delay (tweaking variable)."
api_rate_limit_delay_sec: str = "Delay in seconds between batches to avoid API rate limiting (tweaking variable)."
@dataclass_json @dataclass_json