perf: remove refresh functionality across all apps to improve performance

This commit is contained in:
Admin9705
2025-05-14 18:51:29 -04:00
parent 7939393c25
commit 80f0e287a2
25 changed files with 125 additions and 426 deletions
+5 -60
View File
@@ -139,14 +139,6 @@ const SettingsForms = {
</label>
<p class="setting-help">Skip searching for episodes with future air dates</p>
</div>
<div class="setting-item">
<label for="sonarr_skip_series_refresh"><a href="https://huntarr.io" class="info-icon" title="Learn more about skipping series refresh" target="_blank" rel="noopener"><i class="fas fa-info-circle"></i></a>&nbsp;&nbsp;&nbsp;Skip Series Refresh:</label>
<label class="toggle-switch">
<input type="checkbox" id="sonarr_skip_series_refresh" name="skip_series_refresh" ${settings.skip_series_refresh === true ? 'checked' : ''}>
<span class="toggle-slider"></span>
</label>
<p class="setting-help">Skip refreshing series metadata before searching</p>
</div>
</div>
`;
@@ -287,14 +279,6 @@ const SettingsForms = {
</select>
<p class="setting-help">Select which release date type to use when determining if a movie is considered a future release</p>
</div>
<div class="setting-item">
<label for="skip_movie_refresh"><a href="https://huntarr.io" class="info-icon" title="Learn more about skipping movie refresh" target="_blank" rel="noopener"><i class="fas fa-info-circle"></i></a>&nbsp;&nbsp;&nbsp;Skip Movie Refresh:</label>
<label class="toggle-switch">
<input type="checkbox" id="skip_movie_refresh" ${settings.skip_movie_refresh === true ? 'checked' : ''}>
<span class="toggle-slider"></span>
</label>
<p class="setting-help">Skip refreshing movie metadata before searching</p>
</div>
</div>
`;
@@ -445,14 +429,6 @@ const SettingsForms = {
</label>
<p class="setting-help">Skip searching for albums with future release dates</p>
</div>
<div class="setting-item">
<label for="skip_artist_refresh"><a href="https://huntarr.io" class="info-icon" title="Learn more about skipping artist refresh" target="_blank" rel="noopener"><i class="fas fa-info-circle"></i></a>&nbsp;&nbsp;&nbsp;Skip Artist Refresh:</label>
<label class="toggle-switch">
<input type="checkbox" id="skip_artist_refresh" ${settings.skip_artist_refresh === true ? 'checked' : ''}>
<span class="toggle-slider"></span>
</label>
<p class="setting-help">Skip refreshing artist metadata before searching</p>
</div>
</div>
`;
@@ -580,14 +556,6 @@ const SettingsForms = {
</label>
<p class="setting-help">Skip searching for books with future release dates</p>
</div>
<div class="setting-item">
<label for="skip_author_refresh"><a href="https://huntarr.io" class="info-icon" title="Learn more about skipping author refresh" target="_blank" rel="noopener"><i class="fas fa-info-circle"></i></a>&nbsp;&nbsp;&nbsp;Skip Author Refresh:</label>
<label class="toggle-switch">
<input type="checkbox" id="skip_author_refresh" ${settings.skip_author_refresh === true ? 'checked' : ''}>
<span class="toggle-slider"></span>
</label>
<p class="setting-help">Skip refreshing author metadata before searching</p>
</div>
</div>
`;
@@ -713,22 +681,6 @@ const SettingsForms = {
</label>
<p class="setting-help">Skip searching for scenes with future release dates</p>
</div>
<div class="setting-item">
<label for="whisparr_skip_series_refresh"><a href="https://huntarr.io" class="info-icon" title="Learn more about skipping series refresh" target="_blank" rel="noopener"><i class="fas fa-info-circle"></i></a>&nbsp;&nbsp;&nbsp;Skip Series Refresh:</label>
<label class="toggle-switch">
<input type="checkbox" id="whisparr_skip_series_refresh" name="skip_series_refresh" ${settings.skip_series_refresh === true ? 'checked' : ''}>
<span class="toggle-slider"></span>
</label>
<p class="setting-help">Skip refreshing series metadata before searching</p>
</div>
<div class="setting-item">
<label for="whisparr_skip_scene_refresh"><a href="https://huntarr.io" class="info-icon" title="Learn more about skipping scene refresh" target="_blank" rel="noopener"><i class="fas fa-info-circle"></i></a>&nbsp;&nbsp;&nbsp;Skip Scene Refresh:</label>
<label class="toggle-switch">
<input type="checkbox" id="whisparr_skip_scene_refresh" name="skip_scene_refresh" ${settings.skip_scene_refresh === true ? 'checked' : ''}>
<span class="toggle-slider"></span>
</label>
<p class="setting-help">Skip refreshing scene info before searching</p>
</div>
</div>
`;
@@ -868,14 +820,6 @@ const SettingsForms = {
</label>
<p class="setting-help">Skip searching for scenes with future release dates</p>
</div>
<div class="setting-item">
<label for="eros_skip_item_refresh"><a href="https://huntarr.io" class="info-icon" title="Learn more about skipping item refresh" target="_blank" rel="noopener"><i class="fas fa-info-circle"></i></a>&nbsp;&nbsp;&nbsp;Skip Movie/Scene Refresh:</label>
<label class="toggle-switch">
<input type="checkbox" id="eros_skip_item_refresh" name="skip_item_refresh" ${settings.skip_item_refresh === true ? 'checked' : ''}>
<span class="toggle-slider"></span>
</label>
<p class="setting-help">Skip refreshing movie metadata before searching (strongly recommended to enable this for Whisparr V3)</p>
</div>
</div>
`;
@@ -1175,7 +1119,7 @@ const SettingsForms = {
settings.hourly_cap = getInputValue('#sonarr_hourly_cap', 20);
settings.monitored_only = getInputValue('#sonarr_monitored_only', true);
settings.skip_future_episodes = getInputValue('#sonarr_skip_future_episodes', true);
settings.skip_series_refresh = getInputValue('#sonarr_skip_series_refresh', false);
}
else if (appType === 'radarr') {
settings.hunt_missing_movies = getInputValue('#radarr_hunt_missing_movies', 1);
@@ -1184,7 +1128,7 @@ const SettingsForms = {
settings.hourly_cap = getInputValue('#radarr_hourly_cap', 20);
settings.monitored_only = getInputValue('#radarr_monitored_only', true);
settings.skip_future_releases = getInputValue('#radarr_skip_future_releases', true);
settings.skip_movie_refresh = getInputValue('#radarr_skip_movie_refresh', false);
settings.release_type = getInputValue('#radarr_release_type', 'physical');
}
else if (appType === 'lidarr') {
@@ -1200,7 +1144,7 @@ const SettingsForms = {
settings.hunt_upgrade_books = getInputValue('#readarr_hunt_upgrade_books', 0);
settings.monitored_only = getInputValue('#readarr_monitored_only', true);
settings.skip_future_releases = getInputValue('#readarr_skip_future_releases', true);
settings.skip_author_refresh = getInputValue('#readarr_skip_author_refresh', false);
settings.sleep_duration = getInputValue('#readarr_sleep_duration', 900);
settings.hourly_cap = getInputValue('#readarr_hourly_cap', 20);
}
@@ -1210,6 +1154,7 @@ const SettingsForms = {
settings.monitored_only = getInputValue('#whisparr_monitored_only', true);
settings.whisparr_version = getInputValue('#whisparr-api-version', 'v3');
settings.skip_future_releases = getInputValue('#whisparr_skip_future_releases', true);
settings.sleep_duration = getInputValue('#whisparr_sleep_duration', 900);
settings.hourly_cap = getInputValue('#whisparr_hourly_cap', 20);
}
@@ -1219,7 +1164,7 @@ const SettingsForms = {
settings.hunt_upgrade_items = getInputValue('#eros_hunt_upgrade_items', 0);
settings.monitored_only = getInputValue('#eros_monitored_only', true);
settings.skip_future_releases = getInputValue('#eros_skip_future_releases', true);
settings.skip_item_refresh = getInputValue('#eros_skip_item_refresh', false);
settings.sleep_duration = getInputValue('#eros_sleep_duration', 900);
settings.hourly_cap = getInputValue('#eros_hourly_cap', 20);
}
+6 -28
View File
@@ -319,7 +319,8 @@ def get_quality_upgrades(api_url: str, api_key: str, api_timeout: int, monitored
def refresh_item(api_url: str, api_key: str, api_timeout: int, item_id: int) -> int:
"""
Refresh a movie in Whisparr V3.
Refresh functionality has been removed as it was a performance bottleneck.
This function now returns a placeholder command ID without making any API calls.
Args:
api_url: The base URL of the Whisparr V3 API
@@ -328,34 +329,11 @@ def refresh_item(api_url: str, api_key: str, api_timeout: int, item_id: int) ->
item_id: The ID of the movie to refresh
Returns:
The command ID if the refresh was triggered successfully, None otherwise
A placeholder command ID (123) to simulate success
"""
try:
eros_logger.info(f"Explicitly refreshing movie with ID {item_id} via API call")
# In Whisparr V3, we use RefreshMovie command directly with the movieId
payload = {
"name": "RefreshMovie",
"movieId": item_id
}
# Command endpoint
command_endpoint = "command"
# Make the API request
response = arr_request(api_url, api_key, api_timeout, command_endpoint, "POST", payload)
if response and "id" in response:
command_id = response["id"]
eros_logger.info(f"Refresh movie command triggered with ID {command_id} for movie {item_id}")
return command_id
else:
eros_logger.error(f"Failed to trigger refresh command for movie {item_id} - no command ID returned")
return None
except Exception as e:
eros_logger.error(f"Error refreshing movie {item_id}: {str(e)}")
return None
eros_logger.debug(f"Refresh functionality disabled for movie ID: {item_id}")
# Return a placeholder command ID to simulate success without actually refreshing
return 123
def item_search(api_url: str, api_key: str, api_timeout: int, item_ids: List[int]) -> int:
"""
+2 -14
View File
@@ -52,8 +52,7 @@ def process_missing_items(
monitored_only = app_settings.get("monitored_only", True)
skip_future_releases = app_settings.get("skip_future_releases", True)
skip_item_refresh = app_settings.get("skip_item_refresh", False)
eros_logger.info(f"Skip item refresh setting: {skip_item_refresh}")
# skip_item_refresh setting removed as it was a performance bottleneck
search_mode = app_settings.get("search_mode", "movie") # Default to movie mode if not specified
eros_logger.info(f"Using search mode: {search_mode} for missing items")
@@ -179,18 +178,7 @@ def process_missing_items(
add_processed_id("eros", instance_name, str(item_id))
eros_logger.debug(f"Added item ID {item_id} to processed list for {instance_name}")
# Refresh the item information if not skipped
refresh_command_id = None
if not skip_item_refresh:
eros_logger.info(" - Refreshing item information...")
refresh_command_id = eros_api.refresh_item(api_url, api_key, api_timeout, item_id)
if refresh_command_id:
eros_logger.info(f"Triggered refresh command {refresh_command_id}. Waiting a few seconds...")
time.sleep(5) # Basic wait
else:
eros_logger.warning(f"Failed to trigger refresh command for item ID: {item_id}. Proceeding without refresh.")
else:
eros_logger.info(" - Skipping item refresh (skip_item_refresh=true)")
# Refresh functionality has been removed as it was identified as a performance bottleneck
# Check for stop signal before searching
if stop_check():
+2 -12
View File
@@ -51,8 +51,7 @@ def process_cutoff_upgrades(
general_settings = load_settings('general')
monitored_only = app_settings.get("monitored_only", True)
skip_item_refresh = app_settings.get("skip_item_refresh", False)
eros_logger.info(f"Skip item refresh setting: {skip_item_refresh}")
# skip_item_refresh setting removed as it was a performance bottleneck
search_mode = app_settings.get("search_mode", "movie") # Default to movie mode if not specified
eros_logger.info(f"Using search mode: {search_mode} for quality upgrades")
@@ -159,16 +158,7 @@ def process_cutoff_upgrades(
# Refresh the item information if not skipped
refresh_command_id = None
if not skip_item_refresh:
eros_logger.info(" - Refreshing item information...")
refresh_command_id = eros_api.refresh_item(api_url, api_key, api_timeout, item_id)
if refresh_command_id:
eros_logger.info(f"Triggered refresh command {refresh_command_id}. Waiting a few seconds...")
time.sleep(5) # Basic wait
else:
eros_logger.warning(f"Failed to trigger refresh command for item ID: {item_id}. Proceeding without refresh.")
else:
eros_logger.info(" - Skipping item refresh (skip_item_refresh=true)")
# Refresh functionality has been removed as it was identified as a performance bottleneck
# Check for stop signal before searching
if stop_check():
+10 -13
View File
@@ -434,20 +434,17 @@ def search_artist(api_url: str, api_key: str, api_timeout: int, artist_id: int)
return None
def refresh_artist(api_url: str, api_key: str, api_timeout: int, artist_id: int) -> Optional[Dict]:
"""Trigger a refresh for a specific artist in Lidarr."""
payload = {
"name": "RefreshArtist",
"artistId": artist_id
"""Refresh functionality has been removed as it was a performance bottleneck.
This function now returns a placeholder success value without making any API calls."""
lidarr_logger.debug(f"Refresh functionality disabled for artist ID: {artist_id}")
# Return a placeholder command object to simulate success
return {
'id': 123,
'name': 'RefreshArtist',
'status': 'completed',
'artistId': artist_id,
'message': 'Refresh functionality disabled for performance reasons'
}
response = arr_request(api_url, api_key, api_timeout, "command", method="POST", data=payload)
if response and isinstance(response, dict) and 'id' in response:
command_id = response.get('id')
lidarr_logger.info(f"Triggered Lidarr RefreshArtist for artist ID: {artist_id}. Command ID: {command_id}")
return response # Return the full command object
else:
lidarr_logger.error(f"Failed to trigger Lidarr RefreshArtist for artist ID {artist_id}. Response: {response}")
return None
def get_command_status(api_url: str, api_key: str, api_timeout: int, command_id: int) -> Optional[Dict[str, Any]]:
"""Get the status of a Lidarr command."""
+6 -29
View File
@@ -210,7 +210,8 @@ def get_cutoff_unmet_movies(api_url: str, api_key: str, api_timeout: int, monito
def refresh_movie(api_url: str, api_key: str, api_timeout: int, movie_id: int,
command_wait_delay: int = 1, command_wait_attempts: int = 600) -> Optional[int]:
"""
Refresh a movie in Radarr.
Refresh functionality has been removed as it was a performance bottleneck.
This function now returns a placeholder success value without making any API calls.
Args:
api_url: The base URL of the Radarr API
@@ -221,35 +222,11 @@ def refresh_movie(api_url: str, api_key: str, api_timeout: int, movie_id: int,
command_wait_attempts: Maximum number of status check attempts
Returns:
The command ID if the refresh was triggered successfully, None otherwise
A placeholder command ID (123) to simulate success
"""
endpoint = "command"
data = {
"name": "RefreshMovie",
"movieIds": [movie_id]
}
# Use the updated arr_request
response = arr_request(api_url, api_key, api_timeout, endpoint, method="POST", data=data)
if response and 'id' in response:
command_id = response['id']
radarr_logger.debug(f"Triggered refresh for movie ID {movie_id}. Command ID: {command_id}")
# Wait for command to complete if requested
if command_wait_delay > 0 and command_wait_attempts > 0:
radarr_logger.debug(f"Waiting for refresh command {command_id} to complete...")
success = wait_for_command(api_url, api_key, api_timeout, command_id,
delay_seconds=command_wait_delay,
max_attempts=command_wait_attempts)
if success:
radarr_logger.debug(f"Refresh command {command_id} completed successfully")
else:
radarr_logger.warning(f"Timed out waiting for refresh command {command_id} to complete")
return command_id
else:
radarr_logger.error(f"Failed to trigger refresh command for movie ID {movie_id}. Response: {response}")
return None
radarr_logger.debug(f"Refresh functionality disabled for movie ID: {movie_id}")
# Return a placeholder command ID (123) to simulate success without actually refreshing
return 123
def movie_search(api_url: str, api_key: str, api_timeout: int, movie_ids: List[int]) -> Optional[int]:
"""
+3 -9
View File
@@ -47,7 +47,7 @@ def process_missing_movies(
api_timeout = get_advanced_setting("api_timeout", 120) # Use general.json value
monitored_only = app_settings.get("monitored_only", True)
skip_future_releases = app_settings.get("skip_future_releases", True)
skip_movie_refresh = app_settings.get("skip_movie_refresh", False)
# skip_movie_refresh setting removed as it was a performance bottleneck
hunt_missing_movies = app_settings.get("hunt_missing_movies", 0)
# Use advanced settings from general.json for command operations
@@ -58,7 +58,7 @@ def process_missing_movies(
radarr_logger.info(f"Hunt Missing Movies: {hunt_missing_movies}")
radarr_logger.info(f"Monitored Only: {monitored_only}")
radarr_logger.info(f"Skip Future Releases: {skip_future_releases}")
radarr_logger.info(f"Skip Movie Refresh: {skip_movie_refresh}")
# Skip Movie Refresh setting has been removed
radarr_logger.info(f"Release Type for Future Status: {release_type}")
release_type_field = 'physicalRelease'
@@ -167,13 +167,7 @@ def process_missing_movies(
movie_id = movie.get("id")
movie_title = movie.get("title", "Unknown Title")
# Optional: Refresh the movie before searching
if not skip_movie_refresh:
radarr_logger.info(f"Refreshing movie metadata for '{movie_title}' (ID: {movie_id})...")
refresh_success = radarr_api.refresh_movie(api_url, api_key, api_timeout, movie_id, command_wait_delay, command_wait_attempts)
if not refresh_success:
radarr_logger.warning(f"Failed to refresh movie metadata for '{movie_title}'. Continuing anyway...")
# Refresh functionality has been removed as it was identified as a performance bottleneck
# Search for the movie
radarr_logger.info(f"Searching for movie '{movie_title}' (ID: {movie_id})...")
+2 -9
View File
@@ -39,7 +39,7 @@ def process_cutoff_upgrades(
api_key = app_settings.get("api_key", "").strip()
api_timeout = get_advanced_setting("api_timeout", 120) # Use general.json value
monitored_only = app_settings.get("monitored_only", True)
skip_movie_refresh = app_settings.get("skip_movie_refresh", False)
# skip_movie_refresh setting removed as it was a performance bottleneck
hunt_upgrade_movies = app_settings.get("hunt_upgrade_movies", 0)
# Use advanced settings from general.json for command operations
@@ -92,14 +92,7 @@ def process_cutoff_upgrades(
radarr_logger.info(f"Processing upgrade for movie: \"{movie_title}\" ({movie_year}) (Movie ID: {movie_id})")
# Refresh movie (optional)
if not skip_movie_refresh:
radarr_logger.info(f" - Refreshing movie info...")
refresh_result = radarr_api.refresh_movie(api_url, api_key, api_timeout, movie_id)
if not refresh_result:
radarr_logger.warning(f" - Failed to trigger movie refresh. Continuing search anyway.")
else:
radarr_logger.debug(f" - Skipping movie refresh (skip_movie_refresh=true)")
# Refresh functionality has been removed as it was identified as a performance bottleneck
# Search for cutoff upgrade
radarr_logger.info(f" - Searching for quality upgrade...")
+6 -15
View File
@@ -340,8 +340,8 @@ def get_wanted_missing_books(api_url: str, api_key: str, api_timeout: int, monit
def refresh_author(author_id: int, api_url: Optional[str] = None, api_key: Optional[str] = None, api_timeout: Optional[int] = None) -> bool:
"""
Refresh an author in Readarr.
Accepts optional API credentials.
Refresh functionality has been removed as it was a performance bottleneck.
This function now returns a success value without making any API calls.
Args:
author_id: The ID of the author to refresh
@@ -350,20 +350,11 @@ def refresh_author(author_id: int, api_url: Optional[str] = None, api_key: Optio
api_timeout: Optional API timeout
Returns:
True if the refresh was successful, False otherwise
Always returns True to simulate success
"""
endpoint = f"command"
data = {
"name": "RefreshAuthor",
"authorId": author_id
}
# Pass credentials to arr_request
response = arr_request(endpoint, method="POST", data=data, api_url=api_url, api_key=api_key, api_timeout=api_timeout)
if response:
logger.debug(f"Refreshed author ID {author_id}")
return True
return False
logger.debug(f"Refresh functionality disabled for author ID: {author_id}")
# Always return success without making any API calls
return True
def book_search(book_ids: List[int], api_url: Optional[str] = None, api_key: Optional[str] = None, api_timeout: Optional[int] = None) -> bool:
"""
+2 -10
View File
@@ -51,7 +51,7 @@ def process_missing_books(
monitored_only = app_settings.get("monitored_only", True)
skip_future_releases = app_settings.get("skip_future_releases", True)
skip_author_refresh = app_settings.get("skip_author_refresh", False)
# skip_author_refresh setting removed as it was a performance bottleneck
hunt_missing_books = app_settings.get("hunt_missing_books", 0)
# Use advanced settings from general.json for command operations
@@ -115,15 +115,7 @@ def process_missing_books(
readarr_logger.info(f"Processing missing books for author: \"{author_name}\" (Author ID: {author_id})")
# Refresh author (optional)
if not skip_author_refresh:
readarr_logger.info(f" - Refreshing author info...")
refresh_result = readarr_api.refresh_author(author_id, api_url, api_key, api_timeout)
time.sleep(5) # Basic wait
if not refresh_result:
readarr_logger.warning(f" - Failed to trigger author refresh. Continuing search anyway.")
else:
readarr_logger.info(f" - Skipping author refresh (skip_author_refresh=true)")
# Refresh functionality has been removed as it was identified as a performance bottleneck
# Search for missing books associated with the author
readarr_logger.info(f" - Searching for missing books...")
+1 -1
View File
@@ -55,7 +55,7 @@ def process_cutoff_upgrades(
# Extract necessary settings
instance_name = app_settings.get("instance_name", "Readarr Default")
monitored_only = app_settings.get("monitored_only", True)
skip_author_refresh = app_settings.get("skip_author_refresh", False)
# skip_author_refresh setting removed as it was a performance bottleneck
hunt_upgrade_books = app_settings.get("hunt_upgrade_books", 0)
command_wait_delay = app_settings.get("command_wait_delay", 5)
command_wait_attempts = app_settings.get("command_wait_attempts", 12)
+6 -18
View File
@@ -839,24 +839,12 @@ def get_download_queue_size(api_url: str, api_key: str, api_timeout: int) -> int
return -1
def refresh_series(api_url: str, api_key: str, api_timeout: int, series_id: int) -> Optional[Union[int, str]]:
"""Trigger a refresh for a specific series in Sonarr."""
try:
endpoint = f"{api_url}/api/v3/command"
payload = {
"name": "RefreshSeries",
"seriesId": series_id
}
response = requests.post(endpoint, headers={"X-Api-Key": api_key}, json=payload, timeout=api_timeout)
response.raise_for_status()
command_id = response.json().get('id')
sonarr_logger.info(f"Triggered Sonarr refresh for series ID: {series_id}. Command ID: {command_id}")
return command_id
except requests.exceptions.RequestException as e:
sonarr_logger.error(f"Error triggering Sonarr refresh for series ID {series_id}: {e}")
return None
except Exception as e:
sonarr_logger.error(f"An unexpected error occurred while triggering Sonarr series refresh: {e}")
return None
"""Refresh functionality has been removed as it was a performance bottleneck.
This function now returns a placeholder success value without making any API calls.
"""
sonarr_logger.debug(f"Refresh functionality disabled for series ID: {series_id}")
# Return a placeholder command ID (123) to simulate success without actually refreshing
return 123
def get_series_by_id(api_url: str, api_key: str, api_timeout: int, series_id: int) -> Optional[Dict[str, Any]]:
"""Get series details by ID from Sonarr."""
+6 -29
View File
@@ -23,7 +23,7 @@ def process_missing_episodes(
api_timeout: int = get_advanced_setting("api_timeout", 120),
monitored_only: bool = True,
skip_future_episodes: bool = True,
skip_series_refresh: bool = False,
hunt_missing_items: int = 5,
hunt_missing_mode: str = "episodes",
command_wait_delay: int = get_advanced_setting("command_wait_delay", 1),
@@ -55,7 +55,7 @@ def process_missing_episodes(
sonarr_logger.info("Season [Packs] mode selected - searching for complete season packs")
return process_missing_seasons_packs_mode(
api_url, api_key, instance_name, api_timeout, monitored_only,
skip_series_refresh, hunt_missing_items,
hunt_missing_items,
command_wait_delay, command_wait_attempts, stop_check
)
elif hunt_missing_mode == "shows":
@@ -63,7 +63,7 @@ def process_missing_episodes(
sonarr_logger.info("Show-based missing mode selected")
return process_missing_shows_mode(
api_url, api_key, instance_name, api_timeout, monitored_only,
skip_future_episodes, skip_series_refresh, hunt_missing_items,
skip_future_episodes, hunt_missing_items,
command_wait_delay, command_wait_attempts, stop_check
)
else:
@@ -160,22 +160,7 @@ def process_missing_episodes_mode(
series_title = series_titles.get(series_id, f"Series ID {series_id}")
sonarr_logger.info(f"Processing series: {series_title} (ID: {series_id}) with {len(episode_ids)} missing episodes.")
# Refresh series metadata if not skipped
refresh_command_id = None
if not skip_series_refresh:
sonarr_logger.debug(f"Attempting to refresh series ID: {series_id}")
refresh_command_id = sonarr_api.refresh_series(api_url, api_key, api_timeout, series_id)
if refresh_command_id:
# Wait for refresh command to complete
if not wait_for_command(
api_url, api_key, api_timeout, refresh_command_id,
command_wait_delay, command_wait_attempts, "Series Refresh", stop_check
):
sonarr_logger.warning(f"Series refresh command (ID: {refresh_command_id}) for series {series_id} did not complete successfully or timed out. Proceeding with search anyway.")
else:
sonarr_logger.warning(f"Failed to trigger refresh command for series ID: {series_id}. Proceeding without refresh.")
else:
sonarr_logger.debug(f"Skipping series refresh for series ID: {series_id} as configured.")
# Refresh functionality has been removed as it was identified as a performance bottleneck
if stop_check(): sonarr_logger.info("Stop requested after series refresh attempt."); break
@@ -334,15 +319,7 @@ def process_missing_seasons_packs_mode(
series_title = season['series_title']
episode_count = season['episode_count']
# Refresh series metadata if not skipped
if not skip_series_refresh:
sonarr_logger.debug(f"Refreshing metadata for {series_title} before season pack search")
refresh_command_id = sonarr_api.refresh_series(api_url, api_key, api_timeout, series_id)
if refresh_command_id:
wait_for_command(
api_url, api_key, api_timeout, refresh_command_id,
command_wait_delay, command_wait_attempts, "Series Refresh", stop_check
)
# Refresh functionality has been removed as it was identified as a performance bottleneck
sonarr_logger.info(f"Searching for season pack: {series_title} - Season {season_number} (contains {episode_count} missing episodes)")
@@ -479,7 +456,7 @@ def process_missing_shows_mode(
sonarr_logger.debug(f" ... and {len(missing_episodes)-5} more episodes.")
# Refresh series if not skipped
if not skip_series_refresh:
# Refresh functionality has been removed
sonarr_logger.info(f"Refreshing series info for {show_title}...")
refresh_command_id = sonarr_api.refresh_series(api_url, api_key, api_timeout, show_id)
if refresh_command_id:
+49 -69
View File
@@ -22,7 +22,7 @@ def process_cutoff_upgrades(
instance_name: str,
api_timeout: int = get_advanced_setting("api_timeout", 120),
monitored_only: bool = True,
skip_series_refresh: bool = False,
hunt_upgrade_items: int = 5,
upgrade_mode: str = "episodes",
command_wait_delay: int = get_advanced_setting("command_wait_delay", 1),
@@ -45,14 +45,12 @@ def process_cutoff_upgrades(
if upgrade_mode == "seasons_packs":
return process_upgrade_seasons_mode(
api_url, api_key, instance_name, api_timeout, monitored_only,
skip_series_refresh, hunt_upgrade_items,
command_wait_delay, command_wait_attempts, stop_check
hunt_upgrade_items, command_wait_delay, command_wait_attempts, stop_check
)
else: # Default to episodes mode
return process_upgrade_episodes_mode(
api_url, api_key, instance_name, api_timeout, monitored_only,
skip_series_refresh, hunt_upgrade_items,
command_wait_delay, command_wait_attempts, stop_check
hunt_upgrade_items, command_wait_delay, command_wait_attempts, stop_check
)
def process_upgrade_episodes_mode(
@@ -61,7 +59,7 @@ def process_upgrade_episodes_mode(
instance_name: str,
api_timeout: int,
monitored_only: bool,
skip_series_refresh: bool,
hunt_upgrade_items: int,
command_wait_delay: int,
command_wait_attempts: int,
@@ -87,16 +85,16 @@ def process_upgrade_episodes_mode(
return processed_any
# Filter out future episodes for random selection approach
if skip_series_refresh:
now_unix = time.time()
original_count = len(episodes_to_search)
episodes_to_search = [
ep for ep in episodes_to_search
if ep.get('airDateUtc') and time.mktime(time.strptime(ep['airDateUtc'], '%Y-%m-%dT%H:%M:%SZ')) < now_unix
]
skipped_count = original_count - len(episodes_to_search)
if skipped_count > 0:
sonarr_logger.info(f"Skipped {skipped_count} future episodes based on air date for upgrades.")
# Filter future episodes (previously tied to skip_series_refresh)
now_unix = time.time()
original_count = len(episodes_to_search)
episodes_to_search = [
ep for ep in episodes_to_search
if ep.get('airDateUtc') and time.mktime(time.strptime(ep['airDateUtc'], '%Y-%m-%dT%H:%M:%SZ')) < now_unix
]
skipped_count = original_count - len(episodes_to_search)
if skipped_count > 0:
sonarr_logger.info(f"Skipped {skipped_count} future episodes based on air date for upgrades.")
# Filter out already processed episodes for random selection approach
unprocessed_episodes = []
@@ -159,22 +157,7 @@ def process_upgrade_episodes_mode(
series_title = series_titles.get(series_id, f"Series ID {series_id}")
sonarr_logger.info(f"Processing series for upgrades: {series_title} (ID: {series_id}) with {len(episode_ids)} episodes.")
# Refresh series metadata if not skipped
refresh_command_id = None
if not skip_series_refresh:
sonarr_logger.debug(f"Attempting to refresh series ID: {series_id} before upgrade search.")
refresh_command_id = sonarr_api.refresh_series(api_url, api_key, api_timeout, series_id)
if refresh_command_id:
# Wait for refresh command to complete
if not wait_for_command(
api_url, api_key, api_timeout, refresh_command_id,
command_wait_delay, command_wait_attempts, "Series Refresh (Upgrade)", stop_check
):
sonarr_logger.warning(f"Series refresh command (ID: {refresh_command_id}) for series {series_id} did not complete successfully or timed out. Proceeding with upgrade search anyway.")
else:
sonarr_logger.warning(f"Failed to trigger refresh command for series ID: {series_id}. Proceeding without refresh.")
else:
sonarr_logger.debug(f"Skipping series refresh for series ID: {series_id} as configured.")
# Refresh functionality has been removed as it was identified as a performance bottleneck
if stop_check():
sonarr_logger.info("Stop requested after series refresh attempt for upgrades.")
@@ -269,7 +252,7 @@ def process_upgrade_seasons_mode(
instance_name: str,
api_timeout: int,
monitored_only: bool,
skip_series_refresh: bool,
hunt_upgrade_items: int,
command_wait_delay: int,
command_wait_attempts: int,
@@ -294,18 +277,17 @@ def process_upgrade_seasons_mode(
sonarr_logger.info("No cutoff unmet episodes found in Sonarr.")
return False
# Filter out future episodes if configured
if skip_series_refresh:
now_unix = time.time()
original_count = len(cutoff_unmet_episodes)
# Ensure airDateUtc exists and is not None before parsing
cutoff_unmet_episodes = [
ep for ep in cutoff_unmet_episodes
if ep.get('airDateUtc') and time.mktime(time.strptime(ep['airDateUtc'], '%Y-%m-%dT%H:%M:%SZ')) < now_unix
]
skipped_count = original_count - len(cutoff_unmet_episodes)
if skipped_count > 0:
sonarr_logger.info(f"Skipped {skipped_count} future episodes based on air date for upgrades.")
# Always filter out future episodes (previously tied to skip_series_refresh)
now_unix = time.time()
original_count = len(cutoff_unmet_episodes)
# Ensure airDateUtc exists and is not None before parsing
cutoff_unmet_episodes = [
ep for ep in cutoff_unmet_episodes
if ep.get('airDateUtc') and time.mktime(time.strptime(ep['airDateUtc'], '%Y-%m-%dT%H:%M:%SZ')) < now_unix
]
skipped_count = original_count - len(cutoff_unmet_episodes)
if skipped_count > 0:
sonarr_logger.info(f"Skipped {skipped_count} future episodes based on air date for upgrades.")
if stop_check():
sonarr_logger.info("Stop requested during upgrade processing.")
@@ -444,7 +426,7 @@ def process_upgrade_shows_mode(
instance_name: str,
api_timeout: int,
monitored_only: bool,
skip_series_refresh: bool,
hunt_upgrade_items: int,
command_wait_delay: int,
command_wait_attempts: int,
@@ -469,18 +451,17 @@ def process_upgrade_shows_mode(
sonarr_logger.info("No cutoff unmet episodes found in Sonarr.")
return False
# Filter out future episodes if configured
if skip_series_refresh:
now_unix = time.time()
original_count = len(cutoff_unmet_sample)
# Ensure airDateUtc exists and is not None before parsing
cutoff_unmet_sample = [
ep for ep in cutoff_unmet_sample
if ep.get('airDateUtc') and time.mktime(time.strptime(ep['airDateUtc'], '%Y-%m-%dT%H:%M:%SZ')) < now_unix
]
skipped_count = original_count - len(cutoff_unmet_sample)
if skipped_count > 0:
sonarr_logger.info(f"Skipped {skipped_count} future episodes based on air date for upgrades.")
# Always filter out future episodes (previously tied to skip_series_refresh)
now_unix = time.time()
original_count = len(cutoff_unmet_sample)
# Ensure airDateUtc exists and is not None before parsing
cutoff_unmet_sample = [
ep for ep in cutoff_unmet_sample
if ep.get('airDateUtc') and time.mktime(time.strptime(ep['airDateUtc'], '%Y-%m-%dT%H:%M:%SZ')) < now_unix
]
skipped_count = original_count - len(cutoff_unmet_sample)
if skipped_count > 0:
sonarr_logger.info(f"Skipped {skipped_count} future episodes based on air date for upgrades.")
if stop_check():
sonarr_logger.info("Stop requested during upgrade processing.")
@@ -528,17 +509,16 @@ def process_upgrade_shows_mode(
all_series_episodes = sonarr_api.get_cutoff_unmet_episodes_for_series(
api_url, api_key, api_timeout, series_id, monitored_only)
# Filter future episodes if needed
if skip_series_refresh:
now_unix = time.time()
original_count = len(all_series_episodes)
all_series_episodes = [
ep for ep in all_series_episodes
if ep.get('airDateUtc') and time.mktime(time.strptime(ep['airDateUtc'], '%Y-%m-%dT%H:%M:%SZ')) < now_unix
]
filtered_count = original_count - len(all_series_episodes)
if filtered_count > 0:
sonarr_logger.info(f"Filtered {filtered_count} future episodes from {series_title}")
# Always filter future episodes (previously tied to skip_series_refresh)
now_unix = time.time()
original_count = len(all_series_episodes)
all_series_episodes = [
ep for ep in all_series_episodes
if ep.get('airDateUtc') and time.mktime(time.strptime(ep['airDateUtc'], '%Y-%m-%dT%H:%M:%SZ')) < now_unix
]
filtered_count = original_count - len(all_series_episodes)
if filtered_count > 0:
sonarr_logger.info(f"Filtered {filtered_count} future episodes from {series_title}")
episode_ids = [episode["id"] for episode in all_series_episodes]
+6 -70
View File
@@ -232,7 +232,8 @@ def get_cutoff_unmet_items(api_url: str, api_key: str, api_timeout: int, monitor
def refresh_item(api_url: str, api_key: str, api_timeout: int, item_id: int) -> int:
"""
Refresh an item in Whisparr.
Refresh functionality has been removed as it was a performance bottleneck.
This function now returns a placeholder command ID without making any API calls.
Args:
api_url: The base URL of the Whisparr API
@@ -241,76 +242,11 @@ def refresh_item(api_url: str, api_key: str, api_timeout: int, item_id: int) ->
item_id: The ID of the item to refresh
Returns:
The command ID if the refresh was triggered successfully, None otherwise
A placeholder command ID (123) to simulate success
"""
try:
whisparr_logger.debug(f"Refreshing item with ID {item_id}")
# Some Whisparr versions have issues with RefreshEpisode, try a safer approach
# Use series refresh instead if we can get the series ID from the episode
# First, attempt to get the episode details
episode_endpoint = f"episode/{item_id}"
episode_data = arr_request(api_url, api_key, api_timeout, episode_endpoint)
if episode_data and "seriesId" in episode_data:
# We have the series ID, use series refresh which is more reliable
series_id = episode_data["seriesId"]
whisparr_logger.debug(f"Retrieved series ID {series_id} for episode {item_id}, using series refresh")
# RefreshSeries is generally more reliable
payload = {
"name": "RefreshSeries",
"seriesId": series_id
}
else:
# Fall back to episode refresh if we can't get the series ID
whisparr_logger.debug(f"Could not retrieve series ID for episode {item_id}, using episode refresh")
payload = {
"name": "RefreshEpisode",
"episodeIds": [item_id]
}
# For commands, we need to directly try both path formats since command endpoints
# may have different structures in different Whisparr versions
command_endpoint = "command"
url = f"{api_url.rstrip('/')}/api/{command_endpoint}"
backup_url = f"{api_url.rstrip('/')}/api/v3/{command_endpoint}"
headers = {
"X-Api-Key": api_key,
"Content-Type": "application/json"
}
# Try standard API path first
whisparr_logger.debug(f"Attempting command with standard API path: {url}")
try:
response = session.post(url, headers=headers, json=payload, timeout=api_timeout)
# If we get a 404 or 405, try the v3 path
if response.status_code in [404, 405]:
whisparr_logger.debug(f"Standard path returned {response.status_code}, trying with V3 path: {backup_url}")
response = session.post(backup_url, headers=headers, json=payload, timeout=api_timeout)
response.raise_for_status()
result = response.json()
if result and "id" in result:
command_id = result["id"]
whisparr_logger.debug(f"Refresh command triggered with ID {command_id}")
return command_id
else:
whisparr_logger.error("Failed to trigger refresh command - no command ID returned")
return None
except requests.exceptions.HTTPError as e:
whisparr_logger.error(f"HTTP error during refresh command: {e}, Status Code: {response.status_code}")
whisparr_logger.debug(f"Response content: {response.text[:200]}")
return None
except Exception as e:
whisparr_logger.error(f"Error sending refresh command: {e}")
return None
except Exception as e:
whisparr_logger.error(f"Error refreshing item: {str(e)}")
return None
whisparr_logger.debug(f"Refresh functionality disabled for item ID: {item_id}")
# Return a placeholder command ID to simulate success without actually refreshing
return 123
def item_search(api_url: str, api_key: str, api_timeout: int, item_ids: List[int]) -> int:
"""
+2 -13
View File
@@ -52,7 +52,7 @@ def process_missing_items(
monitored_only = app_settings.get("monitored_only", True)
skip_future_releases = app_settings.get("skip_future_releases", True)
skip_item_refresh = app_settings.get("skip_item_refresh", False)
# skip_item_refresh setting removed as it was a performance bottleneck
# Use the new hunt_missing_items parameter name, falling back to hunt_missing_scenes for backwards compatibility
hunt_missing_items = app_settings.get("hunt_missing_items", app_settings.get("hunt_missing_scenes", 0))
@@ -156,18 +156,7 @@ def process_missing_items(
whisparr_logger.info(f"Processing missing item: \"{title}\" - {season_episode} (Item ID: {item_id})")
# Refresh the item information if not skipped
refresh_command_id = None
if not skip_item_refresh:
whisparr_logger.info(" - Refreshing item information...")
refresh_command_id = whisparr_api.refresh_item(api_url, api_key, api_timeout, item_id)
if refresh_command_id:
whisparr_logger.info(f"Triggered refresh command {refresh_command_id}. Waiting a few seconds...")
time.sleep(5) # Basic wait
else:
whisparr_logger.warning(f"Failed to trigger refresh command for item ID: {item_id}. Proceeding without refresh.")
else:
whisparr_logger.info(" - Skipping item refresh (skip_item_refresh=true)")
# Refresh functionality has been removed as it was identified as a performance bottleneck
# Mark the item as processed BEFORE triggering any searches
add_processed_id("whisparr", instance_name, str(item_id))
+2 -13
View File
@@ -52,7 +52,7 @@ def process_cutoff_upgrades(
command_wait_attempts = get_advanced_setting("command_wait_attempts", 600)
monitored_only = app_settings.get("monitored_only", True)
skip_item_refresh = app_settings.get("skip_item_refresh", False)
# skip_item_refresh setting removed as it was a performance bottleneck
# Use the new hunt_upgrade_items parameter name, falling back to hunt_upgrade_scenes for backwards compatibility
hunt_upgrade_items = app_settings.get("hunt_upgrade_items", app_settings.get("hunt_upgrade_scenes", 0))
@@ -133,18 +133,7 @@ def process_cutoff_upgrades(
whisparr_logger.info(f"Processing item for quality upgrade: \"{title}\" - {season_episode} (Item ID: {item_id})")
whisparr_logger.info(f" - Current quality: {current_quality}")
# Refresh the item information if not skipped
refresh_command_id = None
if not skip_item_refresh:
whisparr_logger.info(" - Refreshing item information...")
refresh_command_id = whisparr_api.refresh_item(api_url, api_key, api_timeout, item_id)
if refresh_command_id:
whisparr_logger.info(f"Triggered refresh command {refresh_command_id}. Waiting a few seconds...")
time.sleep(5) # Basic wait
else:
whisparr_logger.warning(f"Failed to trigger refresh command for item ID: {item_id}. Proceeding without refresh.")
else:
whisparr_logger.info(" - Skipping item refresh (skip_item_refresh=true)")
# Refresh functionality has been removed as it was identified as a performance bottleneck
# Check for stop signal before searching
if stop_check():
-4
View File
@@ -299,7 +299,6 @@ def app_specific_loop(app_type: str) -> None:
api_timeout = combined_settings.get("api_timeout", 120)
monitored_only = combined_settings.get("monitored_only", True)
skip_future_episodes = combined_settings.get("skip_future_episodes", True)
skip_series_refresh = combined_settings.get("skip_series_refresh", False)
hunt_missing_items = combined_settings.get("hunt_missing_items", 0)
hunt_missing_mode = combined_settings.get("hunt_missing_mode", "episodes")
command_wait_delay = combined_settings.get("command_wait_delay", 1)
@@ -313,7 +312,6 @@ def app_specific_loop(app_type: str) -> None:
api_timeout=api_timeout,
monitored_only=monitored_only,
skip_future_episodes=skip_future_episodes,
skip_series_refresh=skip_series_refresh,
hunt_missing_items=hunt_missing_items,
hunt_missing_mode=hunt_missing_mode,
command_wait_delay=command_wait_delay,
@@ -338,7 +336,6 @@ def app_specific_loop(app_type: str) -> None:
api_key = combined_settings.get("api_key", "").strip()
api_timeout = combined_settings.get("api_timeout", 120)
monitored_only = combined_settings.get("monitored_only", True)
skip_series_refresh = combined_settings.get("skip_series_refresh", False)
hunt_upgrade_items = combined_settings.get("hunt_upgrade_items", 0)
upgrade_mode = combined_settings.get("upgrade_mode", "episodes")
command_wait_delay = combined_settings.get("command_wait_delay", 1)
@@ -350,7 +347,6 @@ def app_specific_loop(app_type: str) -> None:
instance_name=instance_name, # Added the required instance_name parameter
api_timeout=api_timeout,
monitored_only=monitored_only,
skip_series_refresh=skip_series_refresh,
hunt_upgrade_items=hunt_upgrade_items,
upgrade_mode=upgrade_mode,
command_wait_delay=command_wait_delay,
+2 -2
View File
@@ -11,9 +11,9 @@
"hunt_upgrade_items": 0,
"sleep_duration": 900,
"monitored_only": true,
"skip_series_refresh": true,
"skip_future_releases": true,
"skip_scene_refresh": true,
"search_mode": "movie",
"hourly_cap": 20
}
+1 -2
View File
@@ -13,6 +13,5 @@
"sleep_duration": 900,
"monitored_only": true,
"hourly_cap": 20,
"skip_future_releases": true,
"skip_artist_refresh": true
"skip_future_releases": true
}
+1 -1
View File
@@ -12,6 +12,6 @@
"sleep_duration": 900,
"monitored_only": true,
"skip_future_releases": true,
"skip_movie_refresh": true,
"hourly_cap": 20
}
+1 -1
View File
@@ -12,6 +12,6 @@
"sleep_duration": 900,
"monitored_only": true,
"skip_future_releases": true,
"skip_author_refresh": true,
"hourly_cap": 20
}
+1 -1
View File
@@ -14,6 +14,6 @@
"sleep_duration": 900,
"monitored_only": true,
"skip_future_episodes": true,
"skip_series_refresh": true,
"hourly_cap": 20
}
+2 -2
View File
@@ -11,8 +11,8 @@
"hunt_upgrade_items": 0,
"sleep_duration": 900,
"monitored_only": true,
"skip_series_refresh": true,
"skip_future_releases": true,
"skip_scene_refresh": true,
"hourly_cap": 20
}
+1 -1
View File
@@ -1 +1 @@
6.5.7
6.5.8