diff --git a/src/server/api/setup_endpoints.py b/src/server/api/setup_endpoints.py index da73583..de11a8f 100644 --- a/src/server/api/setup_endpoints.py +++ b/src/server/api/setup_endpoints.py @@ -224,17 +224,25 @@ async def resolve_unresolved_folder( ) +class SearchFolderRequest(BaseModel): + """Request model for searching an unresolved folder with custom query.""" + query: Optional[str] = Field(None, description="Custom search query override") + + @router.post("/unresolved/{folder_name}/search", response_model=UnresolvedFolderResponse) async def search_unresolved_folder( folder_name: str, + request: Optional[SearchFolderRequest] = None, db=Depends(get_database_session), ) -> UnresolvedFolderResponse: """Re-search for a specific unresolved folder to get fresh suggestions. - Performs a new search using the folder's title and caches the results. + Performs a new search using the folder's title or a custom query. + Caches the results for subsequent display. Args: folder_name: URL-encoded folder name to search for + request: Optional SearchFolderRequest with custom query override Returns: UnresolvedFolderResponse with updated search suggestions @@ -258,10 +266,13 @@ async def search_unresolved_folder( detail=f"Folder already resolved: {folder_name}" ) + # Use custom query if provided, otherwise fall back to folder title + search_query = request.query if request and request.query else folder.title + # Perform search series_app = get_series_app() try: - results = await series_app.search(folder.title) + results = await series_app.search(search_query) search_result_json = json.dumps(results) if results else "[]" except Exception as e: logger.warning( @@ -278,7 +289,7 @@ async def search_unresolved_folder( folder_name=folder.folder_name, title=folder.title, year=folder.year, - search_attempts=folder.search_attempts, + search_attempts=folder.search_attempts + 1, search_suggestions=results, ) diff --git a/src/server/web/templates/unresolved.html b/src/server/web/templates/unresolved.html index 719fbb4..6151aee 100644 --- a/src/server/web/templates/unresolved.html +++ b/src/server/web/templates/unresolved.html @@ -238,6 +238,63 @@ opacity: 0.7; } + .search-again-row { + display: flex; + gap: 0.5rem; + margin-top: 0.5rem; + align-items: center; + } + + .search-again-input { + flex: 1; + padding: 0.5rem 0.75rem; + border: 1px solid var(--color-border); + border-radius: var(--border-radius-md); + font-size: 0.85rem; + background: var(--color-surface); + color: var(--color-text); + } + + .search-again-input:focus { + outline: none; + border-color: var(--color-accent); + } + + .search-again-row .search-again-btn { + margin-top: 0; + } + + .search-again-btn.searching { + pointer-events: none; + opacity: 0.7; + } + + .search-again-row { + display: flex; + gap: 0.5rem; + margin-top: 0.5rem; + align-items: center; + } + + .search-again-input { + flex: 1; + padding: 0.5rem 0.75rem; + border: 1px solid var(--color-border); + border-radius: var(--border-radius-md); + font-size: 0.85rem; + background: var(--color-surface); + color: var(--color-text); + } + + .search-again-input:focus { + outline: none; + border-color: var(--color-accent); + } + + .search-again-row .search-again-btn { + margin-top: 0; + } + /* Empty state */ .empty-state { text-align: center; @@ -471,12 +528,17 @@ return res.json(); } - async function reSearchFolder(folderName) { + async function reSearchFolder(folderName, customQuery) { const token = localStorage.getItem('auth_token'); const encodedName = encodeURIComponent(folderName); + const body = customQuery ? JSON.stringify({ query: customQuery }) : '{}'; const res = await fetch(`/api/setup/unresolved/${encodedName}/search`, { method: 'POST', - headers: { 'Authorization': `Bearer ${token}` } + headers: { + 'Authorization': `Bearer ${token}`, + 'Content-Type': 'application/json' + }, + body: body }); return res.json(); } @@ -497,15 +559,21 @@ ? folder.search_suggestions.map(s => `
`).join('') : '