diff --git a/src/server/api/anime.py b/src/server/api/anime.py index 3f724ad..6f5b2a1 100644 --- a/src/server/api/anime.py +++ b/src/server/api/anime.py @@ -4,10 +4,11 @@ from pathlib import Path from typing import Any, List, Optional from fastapi import APIRouter, Depends, HTTPException, status -from pydantic import BaseModel, Field, field_validator +from pydantic import BaseModel, Field from sqlalchemy.ext.asyncio import AsyncSession from src.config.settings import settings +from src.core.entities.series import Serie from src.core.utils.key_utils import generate_key_from_folder, is_valid_key from src.server.database.service import AnimeSeriesService from src.server.exceptions import ( @@ -232,14 +233,6 @@ class AnimeSummary(BaseModel): default=None, description="ISO timestamp when NFO was last updated" ) - loading_status: Optional[str] = Field( - default=None, - description="Current loading status (e.g., 'completed', 'failed', 'in_progress')" - ) - loading_error: Optional[str] = Field( - default=None, - description="Error message if loading failed (e.g., 'key cannot be None or empty')" - ) tmdb_id: Optional[int] = Field( default=None, description="The Movie Database (TMDB) ID" @@ -438,8 +431,6 @@ async def list_anime( nfo_updated_at=series_dict.get("nfo_updated_at"), tmdb_id=series_dict.get("tmdb_id"), tvdb_id=series_dict.get("tvdb_id"), - loading_status=series_dict.get("loading_status"), - loading_error=series_dict.get("loading_error"), ) ) @@ -1194,346 +1185,6 @@ async def get_anime( ) from exc -class ManualKeyUpdate(BaseModel): - """Request model for manually updating a series key.""" - - key: str = Field( - ..., - min_length=2, - description="New URL-safe key for the series (alphanumeric, hyphens, underscores)" - ) - - -@router.patch("/{anime_key}/manual-key", response_model=dict) -async def update_series_manual_key( - anime_key: str, - update_data: ManualKeyUpdate, - db: AsyncSession = Depends(get_optional_database_session), - series_app: Any = Depends(get_series_app), -) -> dict: - """Manually update the key for a series. - - This endpoint allows users to supply a key for folders that failed - automatic key generation (e.g., non-Latin characters, special symbols). - - Args: - anime_key: Current series key - update_data: New key to assign - db: Database session - series_app: SeriesApp instance for in-memory updates - - Returns: - Updated series info with new key - - Raises: - HTTPException: If validation fails or series not found - """ - new_key = update_data.key.strip() - - # Validate the new key format - if not is_valid_key(new_key): - raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, - detail="Invalid key format. Key must be URL-safe (alphanumeric, hyphens, underscores only)" - ) - - # Find the series - check DB first - series_db = None - if db: - series_db = await AnimeSeriesService.get_by_key(db, anime_key) - - # Also check in-memory list if series_app available - found_in_memory = None - if series_app and hasattr(series_app, "list"): - for serie in series_app.list.GetList(): - if getattr(serie, "key", None) == anime_key: - found_in_memory = serie - break - - if not series_db and not found_in_memory: - raise HTTPException( - status_code=status.HTTP_404_NOT_FOUND, - detail=f"Series with key '{anime_key}' not found" - ) - - # Check if new key is already in use - existing_keys = set() - if db: - all_series = await AnimeSeriesService.get_all(db) - existing_keys = {s.key for s in all_series if s.key != anime_key} - if series_app and hasattr(series_app, "list"): - for serie in series_app.list.GetList(): - key = getattr(serie, "key", None) - if key and key != anime_key: - existing_keys.add(key) - - if new_key in existing_keys: - raise HTTPException( - status_code=status.HTTP_409_CONFLICT, - detail=f"Key '{new_key}' is already in use by another series" - ) - - old_key = anime_key - - # Update in database if found - if series_db: - from src.server.database.connection import get_db - async with get_db() as session: - await AnimeSeriesService.update( - session, - series_db.id, - key=new_key, - loading_error=None # Clear error on successful key update - ) - await session.commit() - - # Update in-memory cache - if found_in_memory: - try: - found_in_memory.key = new_key - logger.info( - "Updated in-memory key for series: %s -> %s", - old_key, - new_key - ) - except ValueError as ve: - raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, - detail=str(ve) - ) - - logger.info( - "Manual key update successful: %s -> %s", - old_key, - new_key - ) - - return { - "success": True, - "old_key": old_key, - "new_key": new_key, - "message": f"Key updated from '{old_key}' to '{new_key}'" - } - - -class MetadataIdsUpdate(BaseModel): - """Request model for manually updating TMDB and TVDB IDs.""" - - tmdb_id: Optional[int] = Field( - default=None, - description="TMDB ID (positive integer, or null to clear)" - ) - tvdb_id: Optional[int] = Field( - default=None, - description="TVDB ID (positive integer, or null to clear)" - ) - - @field_validator("tmdb_id", "tvdb_id") - @classmethod - def validate_positive_or_null(cls, v): - if v is not None and v <= 0: - raise ValueError("ID must be a positive integer or null") - return v - - -@router.patch("/{anime_key}/metadata-ids", response_model=dict) -async def update_series_metadata_ids( - anime_key: str, - update_data: MetadataIdsUpdate, - db: AsyncSession = Depends(get_optional_database_session), - series_app: Any = Depends(get_series_app), -) -> dict: - """Manually update TMDB and TVDB IDs for a series. - - This endpoint allows users to supply missing metadata IDs for series - that failed automatic TMDB lookup. After updating IDs, it triggers - a background NFO re-generation. - - Args: - anime_key: Series key - update_data: TMDB and TVDB IDs to set - db: Database session - series_app: SeriesApp instance for in-memory updates - - Returns: - Updated series info with new IDs - - Raises: - HTTPException: If validation fails or series not found - """ - if update_data.tmdb_id is None and update_data.tvdb_id is None: - raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, - detail="At least one of tmdb_id or tvdb_id must be provided" - ) - - series_db = None - if db: - series_db = await AnimeSeriesService.get_by_key(db, anime_key) - - if not series_db: - raise HTTPException( - status_code=status.HTTP_404_NOT_FOUND, - detail=f"Series with key '{anime_key}' not found" - ) - - update_fields = {} - if update_data.tmdb_id is not None: - update_fields["tmdb_id"] = update_data.tmdb_id - if update_data.tvdb_id is not None: - update_fields["tvdb_id"] = update_data.tvdb_id - - if db: - from datetime import datetime, timezone - update_fields["nfo_updated_at"] = datetime.now(timezone.utc) - update_fields["has_nfo"] = True - - await AnimeSeriesService.update( - db, - series_db.id, - **update_fields - ) - await db.commit() - - # Update in-memory cache if available - if series_app and hasattr(series_app, "list"): - for serie in series_app.list.GetList(): - if getattr(serie, "key", None) == anime_key: - if update_data.tmdb_id is not None: - serie.tmdb_id = update_data.tmdb_id - if update_data.tvdb_id is not None: - serie.tvdb_id = update_data.tvdb_id - break - - # Trigger background NFO re-generation - background_loader = None - try: - background_loader = await get_background_loader_service() - except Exception: - pass - - nfo_queued = False - if background_loader and db: - try: - from src.server.database.connection import get_db_session - async with get_db_session() as bg_db: - series_for_bg = await AnimeSeriesService.get_by_key(bg_db, anime_key) - if series_for_bg: - await background_loader.load_series_nfo( - series_for_bg.key, - series_for_bg.folder, - series_for_bg.name, - force_refresh=True - ) - nfo_queued = True - except Exception as e: - logger.warning("Failed to queue NFO refresh for '%s': %s", anime_key, str(e)) - - logger.info( - "Metadata IDs updated for '%s': tmdb_id=%s, tvdb_id=%s, NFO_queued=%s", - anime_key, - update_data.tmdb_id, - update_data.tvdb_id, - nfo_queued - ) - - return { - "success": True, - "key": anime_key, - "tmdb_id": update_data.tmdb_id, - "tvdb_id": update_data.tvdb_id, - "nfo_refresh_queued": nfo_queued, - "message": "Metadata IDs updated. NFO refresh queued." if nfo_queued - else "Metadata IDs updated." - } - - -@router.post("/{anime_key}/refresh-nfo", response_model=dict) -async def refresh_series_nfo( - anime_key: str, - db: AsyncSession = Depends(get_optional_database_session), - series_app: Any = Depends(get_series_app), -) -> dict: - """Force NFO re-generation for a series using current IDs. - - This endpoint triggers a background NFO re-generation using the - existing TMDB/TVDB IDs (or creating minimal NFO if no IDs exist). - - Args: - anime_key: Series key - db: Database session - series_app: SeriesApp instance - - Returns: - Status of NFO refresh operation - - Raises: - HTTPException: If series not found - """ - if db: - series_db = await AnimeSeriesService.get_by_key(db, anime_key) - - if not db or not series_db: - # Check in-memory - found = None - if series_app and hasattr(series_app, "list"): - for serie in series_app.list.GetList(): - if getattr(serie, "key", None) == anime_key: - found = serie - break - if not found: - raise HTTPException( - status_code=status.HTTP_404_NOT_FOUND, - detail=f"Series with key '{anime_key}' not found" - ) - - background_loader = None - try: - background_loader = await get_background_loader_service() - except Exception: - pass - - if not background_loader: - raise HTTPException( - status_code=status.HTTP_503_SERVICE_UNAVAILABLE, - detail="Background loader service not available" - ) - - series_for_bg = None - if db: - async with get_db_session() as bg_db: - series_for_bg = await AnimeSeriesService.get_by_key(bg_db, anime_key) - - if not series_for_bg: - raise HTTPException( - status_code=status.HTTP_404_NOT_FOUND, - detail=f"Series with key '{anime_key}' not found" - ) - - try: - await background_loader.load_series_nfo( - series_for_bg.key, - series_for_bg.folder, - series_for_bg.name, - force_refresh=True - ) - nfo_queued = True - except Exception as e: - logger.error("Failed to queue NFO refresh for '%s': %s", anime_key, str(e)) - raise HTTPException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, - detail=f"Failed to queue NFO refresh: {str(e)}" - ) - - logger.info("NFO refresh queued for '%s'", anime_key) - - return { - "success": True, - "key": anime_key, - "message": "NFO refresh queued" - } - - # Maximum allowed input size for security MAX_INPUT_LENGTH = 100000 # 100KB diff --git a/src/server/web/static/js/app.js b/src/server/web/static/js/app.js index cb81989..50ad81f 100644 --- a/src/server/web/static/js/app.js +++ b/src/server/web/static/js/app.js @@ -442,23 +442,6 @@ class AniWorldApp { this.hideConfigModal(); }); - // Edit key modal - document.getElementById('close-edit-key').addEventListener('click', () => { - this.hideEditKeyModal(); - }); - - document.getElementById('cancel-edit-key').addEventListener('click', () => { - this.hideEditKeyModal(); - }); - - document.querySelector('#edit-key-modal .modal-overlay').addEventListener('click', () => { - this.hideEditKeyModal(); - }); - - document.getElementById('save-edit-key').addEventListener('click', () => { - this.saveManualKey(); - }); - // Scheduler configuration document.getElementById('scheduled-rescan-enabled').addEventListener('change', () => { this.toggleSchedulerTimeInput(); @@ -1564,72 +1547,6 @@ class AniWorldApp { document.getElementById('config-modal').classList.add('hidden'); } - showEditKeyModal(key, folder) { - this._currentEditKey = key; - document.getElementById('edit-key-folder').textContent = folder; - document.getElementById('edit-key-input').value = ''; - document.getElementById('edit-key-error').classList.add('hidden'); - document.getElementById('edit-key-modal').classList.remove('hidden'); - } - - hideEditKeyModal() { - document.getElementById('edit-key-modal').classList.add('hidden'); - this._currentEditKey = null; - } - - async saveManualKey() { - const oldKey = this._currentEditKey; - const newKey = document.getElementById('edit-key-input').value.trim(); - const errorEl = document.getElementById('edit-key-error'); - - if (!newKey || newKey.length < 2) { - errorEl.textContent = 'Key must be at least 2 characters'; - errorEl.classList.remove('hidden'); - return; - } - - // Validate key format (URL-safe) - if (!/^[a-zA-Z0-9][a-zA-Z0-9_-]*$/.test(newKey)) { - errorEl.textContent = 'Key must be URL-safe (alphanumeric, hyphens, underscores only)'; - errorEl.classList.remove('hidden'); - return; - } - - try { - const response = await this.makeAuthenticatedRequest( - `/api/anime/${encodeURIComponent(oldKey)}/manual-key`, - { - method: 'PATCH', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ key: newKey }) - } - ); - - if (!response) { - errorEl.textContent = 'Failed to update key'; - errorEl.classList.remove('hidden'); - return; - } - - if (response.ok) { - this.hideEditKeyModal(); - this.showToast(`Key updated: ${oldKey} → ${newKey}`, 'success'); - // Reload series list - if (typeof AniWorld.SeriesManager !== 'undefined') { - AniWorld.SeriesManager.loadSeries(); - } - } else { - const data = await response.json().catch(() => ({ detail: 'Update failed' })); - errorEl.textContent = data.detail || 'Failed to update key'; - errorEl.classList.remove('hidden'); - } - } catch (err) { - console.error('Error saving manual key:', err); - errorEl.textContent = 'Error updating key'; - errorEl.classList.remove('hidden'); - } - } - async loadSchedulerConfig() { try { const response = await this.makeAuthenticatedRequest('/api/scheduler/config'); @@ -2427,336 +2344,4 @@ document.addEventListener('DOMContentLoaded', () => { }); // Global functions for inline event handlers -window.app = null; - -/** - * Show the edit key modal - * @param {string} currentKey - The current series key - * @param {string} folderName - The folder name - */ -function showEditKeyModal(currentKey, folderName) { - const modal = document.getElementById('edit-key-modal'); - const overlay = document.getElementById('edit-key-overlay'); - const folderSpan = document.getElementById('edit-key-folder'); - const keyInput = document.getElementById('edit-key-input'); - const errorSpan = document.getElementById('edit-key-error'); - const saveBtn = document.getElementById('edit-key-save'); - - if (!modal || !overlay || !folderSpan || !keyInput) { - console.error('Edit key modal elements not found'); - return; - } - - // Reset state - folderSpan.textContent = folderName; - keyInput.value = currentKey; - keyInput.dataset.originalKey = currentKey; - errorSpan.textContent = ''; - errorSpan.style.display = 'none'; - saveBtn.disabled = false; - - // Show modal - modal.classList.remove('hidden'); - overlay.classList.remove('hidden'); - keyInput.focus(); - keyInput.select(); -} - -/** - * Hide the edit key modal - */ -function hideEditKeyModal() { - const modal = document.getElementById('edit-key-modal'); - const overlay = document.getElementById('edit-key-overlay'); - - if (modal) { - modal.classList.add('hidden'); - } - if (overlay) { - overlay.classList.add('hidden'); - } -} - -/** - * Save the manual key for a series - * @param {string} oldKey - The original key - * @param {string} newKey - The new key to set - */ -async function saveManualKey(oldKey, newKey) { - const errorSpan = document.getElementById('edit-key-error'); - const saveBtn = document.getElementById('edit-key-save'); - - if (!errorSpan || !saveBtn) { - console.error('Edit key modal elements not found'); - return; - } - - errorSpan.textContent = ''; - errorSpan.style.display = 'none'; - saveBtn.disabled = true; - - try { - const response = await fetch(`/api/anime/${encodeURIComponent(oldKey)}/manual-key`, { - method: 'PATCH', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ key: newKey }), - }); - - const data = await response.json(); - - if (!response.ok) { - errorSpan.textContent = data.detail || 'Failed to update key'; - errorSpan.style.display = 'block'; - saveBtn.disabled = false; - return; - } - - // Success - hide modal and reload - hideEditKeyModal(); - showToast('Key updated successfully', 'success'); - - // Reload series list - if (window.app && window.app.loadSeries) { - window.app.loadSeries(); - } else if (typeof loadSeries === 'function') { - loadSeries(); - } else { - location.reload(); - } - } catch (error) { - console.error('Error saving manual key:', error); - errorSpan.textContent = 'Network error: ' + error.message; - errorSpan.style.display = 'block'; - saveBtn.disabled = false; - } -} - -// Current metadata edit state -let _currentEditMetadataKey = null; - -/** - * Show the edit metadata IDs modal - * @param {string} key - The series key - * @param {string} name - The series name - * @param {number|null} currentTmdbId - Current TMDB ID - * @param {number|null} currentTvdbId - Current TVDB ID - */ -function showEditMetadataModal(key, name, currentTmdbId, currentTvdbId) { - const modal = document.getElementById('edit-metadata-modal'); - const overlay = modal ? modal.querySelector('.modal-overlay') : null; - const nameSpan = document.getElementById('edit-metadata-series-name'); - const tmdbInput = document.getElementById('edit-metadata-tmdb'); - const tvdbInput = document.getElementById('edit-metadata-tvdb'); - const errorSpan = document.getElementById('edit-metadata-error'); - const saveBtn = document.getElementById('save-edit-metadata'); - const cancelBtn = document.getElementById('cancel-edit-metadata'); - - if (!modal || !nameSpan || !tmdbInput || !tvdbInput) { - console.error('Edit metadata modal elements not found'); - return; - } - - // Store current key - _currentEditMetadataKey = key; - - // Reset state - nameSpan.textContent = name; - tmdbInput.value = currentTmdbId || ''; - tvdbInput.value = currentTvdbId || ''; - if (errorSpan) { - errorSpan.textContent = ''; - errorSpan.classList.add('hidden'); - } - if (saveBtn) saveBtn.disabled = false; - - // Show modal - modal.classList.remove('hidden'); - if (overlay) overlay.classList.remove('hidden'); - tmdbInput.focus(); -} - -/** - * Hide the edit metadata modal - */ -function hideEditMetadataModal() { - const modal = document.getElementById('edit-metadata-modal'); - if (modal) { - modal.classList.add('hidden'); - } - _currentEditMetadataKey = null; -} - -/** - * Save metadata IDs for a series - * @param {string} key - The series key - * @param {number|null} tmdbId - TMDB ID (null to clear) - * @param {number|null} tvdbId - TVDB ID (null to clear) - */ -async function saveMetadataIds(key, tmdbId, tvdbId) { - const errorSpan = document.getElementById('edit-metadata-error'); - const saveBtn = document.getElementById('save-edit-metadata'); - - if (!errorSpan || !saveBtn) { - console.error('Edit metadata modal elements not found'); - return; - } - - errorSpan.textContent = ''; - errorSpan.classList.add('hidden'); - saveBtn.disabled = true; - - try { - const body = {}; - if (tmdbId !== '') body.tmdb_id = parseInt(tmdbId, 10) || null; - if (tvdbId !== '') body.tvdb_id = parseInt(tvdbId, 10) || null; - - const response = await fetch(`/api/anime/${encodeURIComponent(key)}/metadata-ids`, { - method: 'PATCH', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify(body), - }); - - const data = await response.json(); - - if (!response.ok) { - errorSpan.textContent = data.detail || 'Failed to update metadata IDs'; - errorSpan.classList.remove('hidden'); - saveBtn.disabled = false; - return; - } - - // Success - hide modal and show toast - hideEditMetadataModal(); - showToast('Metadata IDs updated. NFO refresh queued.', 'success'); - - // Reload series list to reflect changes - if (window.app && window.app.loadSeries) { - window.app.loadSeries(); - } else if (typeof loadSeries === 'function') { - loadSeries(); - } - } catch (error) { - console.error('Error saving metadata IDs:', error); - errorSpan.textContent = 'Network error: ' + error.message; - errorSpan.classList.remove('hidden'); - saveBtn.disabled = false; - } -} - -/** - * Refresh NFO for a series - * @param {string} key - The series key - */ -async function refreshSeriesNfo(key) { - try { - const response = await fetch(`/api/anime/${encodeURIComponent(key)}/refresh-nfo`, { - method: 'POST', - }); - - const data = await response.json(); - - if (!response.ok) { - showToast('Failed to refresh NFO: ' + (data.detail || 'Unknown error'), 'error'); - return; - } - - showToast('NFO refresh queued', 'success'); - } catch (error) { - console.error('Error refreshing NFO:', error); - showToast('Network error: ' + error.message, 'error'); - } -} - -// Bind edit metadata modal events if modal exists -document.addEventListener('DOMContentLoaded', () => { - const modal = document.getElementById('edit-metadata-modal'); - const overlay = modal ? modal.querySelector('.modal-overlay') : null; - const cancelBtn = document.getElementById('cancel-edit-metadata'); - const saveBtn = document.getElementById('save-edit-metadata'); - const tmdbInput = document.getElementById('edit-metadata-tmdb'); - const tvdbInput = document.getElementById('edit-metadata-tvdb'); - - if (cancelBtn) { - cancelBtn.addEventListener('click', hideEditMetadataModal); - } - - if (overlay) { - overlay.addEventListener('click', hideEditMetadataModal); - } - - if (saveBtn && tmdbInput && tvdbInput) { - saveBtn.addEventListener('click', () => { - if (_currentEditMetadataKey) { - saveMetadataIds( - _currentEditMetadataKey, - tmdbInput.value, - tvdbInput.value - ); - } - }); - } - - if (tmdbInput) { - tmdbInput.addEventListener('keydown', (e) => { - if (e.key === 'Enter') { - e.preventDefault(); - saveBtn.click(); - } else if (e.key === 'Escape') { - hideEditMetadataModal(); - } - }); - } - - if (tvdbInput) { - tvdbInput.addEventListener('keydown', (e) => { - if (e.key === 'Enter') { - e.preventDefault(); - saveBtn.click(); - } else if (e.key === 'Escape') { - hideEditMetadataModal(); - } - }); - } -}); - -// Bind edit key modal events if modal exists -document.addEventListener('DOMContentLoaded', () => { - const modal = document.getElementById('edit-key-modal'); - const overlay = document.getElementById('edit-key-overlay'); - const cancelBtn = document.getElementById('edit-key-cancel'); - const saveBtn = document.getElementById('edit-key-save'); - const keyInput = document.getElementById('edit-key-input'); - - if (cancelBtn) { - cancelBtn.addEventListener('click', hideEditKeyModal); - } - - if (overlay) { - overlay.addEventListener('click', hideEditKeyModal); - } - - if (saveBtn && keyInput) { - saveBtn.addEventListener('click', () => { - const originalKey = keyInput.dataset.originalKey; - const newKey = keyInput.value.trim(); - if (newKey && newKey !== originalKey) { - saveManualKey(originalKey, newKey); - } - }); - } - - if (keyInput) { - keyInput.addEventListener('keydown', (e) => { - if (e.key === 'Enter') { - e.preventDefault(); - saveBtn.click(); - } else if (e.key === 'Escape') { - hideEditKeyModal(); - } - }); - } -}); \ No newline at end of file +window.app = null; \ No newline at end of file diff --git a/src/server/web/static/js/index/series-manager.js b/src/server/web/static/js/index/series-manager.js index bb446ad..a4acda5 100644 --- a/src/server/web/static/js/index/series-manager.js +++ b/src/server/web/static/js/index/series-manager.js @@ -40,31 +40,6 @@ AniWorld.SeriesManager = (function() { if (sortBtn) { sortBtn.addEventListener('click', toggleAlphabeticalSort); } - - // Event delegation for dynamically created edit-key buttons - document.addEventListener('click', function(e) { - const editKeyBtn = e.target.closest('.edit-key-btn'); - if (editKeyBtn) { - e.preventDefault(); - const key = editKeyBtn.dataset.key; - const folder = editKeyBtn.dataset.folder; - if (window.showEditKeyModal) { - window.showEditKeyModal(key, folder); - } - } - - const editMetadataBtn = e.target.closest('.edit-metadata-btn'); - if (editMetadataBtn) { - e.preventDefault(); - const key = editMetadataBtn.dataset.key; - const name = editMetadataBtn.dataset.name; - const tmdbId = editMetadataBtn.dataset.tmdbId || null; - const tvdbId = editMetadataBtn.dataset.tvdbId || null; - if (window.showEditMetadataModal) { - window.showEditMetadataModal(key, name, tmdbId, tvdbId); - } - } - }); } /** @@ -368,8 +343,7 @@ AniWorld.SeriesManager = (function() { const canBeSelected = hasMissingEpisodes; const hasNfo = serie.has_nfo || false; const isLoading = serie.loading_status && serie.loading_status !== 'completed' && serie.loading_status !== 'failed'; - const hasKeyError = serie.loading_error && serie.loading_error.includes('key cannot be None or empty'); - + // Debug logging for troubleshooting if (serie.key === 'so-im-a-spider-so-what') { console.log('[createSerieCard] Spider series:', { @@ -382,12 +356,6 @@ AniWorld.SeriesManager = (function() { }); } - const editKeyBtn = hasKeyError - ? '' - : ''; - - const editMetadataBtn = ''; - return '
' + AniWorld.UI.escapeHtml(serie.folder) + '
' + '' + '
' + - (hasKeyError ? '' : '') + (hasMissingEpisodes ? '' : '') + (hasNfo ? '' : '') + - editMetadataBtn + - editKeyBtn + '
' + '' + '
' + diff --git a/src/server/web/templates/index.html b/src/server/web/templates/index.html index 0b31794..5ef9ae1 100644 --- a/src/server/web/templates/index.html +++ b/src/server/web/templates/index.html @@ -640,88 +640,6 @@
- - - - - -