From dcace84406ed6acb98284f9b5f5b36823b6c4495 Mon Sep 17 00:00:00 2001 From: sbcrumb Date: Tue, 14 Oct 2025 15:18:08 -0400 Subject: [PATCH] fix: search issues in webinterfacey --- api/routes.py | 18 ++- api/web_routes.py | 133 ++++++++++++++++- static/css/styles.css | 142 ++++++++++++++++++ static/index.html | 61 +++++--- static/js/app.js | 336 +++++++++++++++++++++++++++++++++++------- 5 files changed, 619 insertions(+), 71 deletions(-) diff --git a/api/routes.py b/api/routes.py index fa135bb..0c4d4e3 100644 --- a/api/routes.py +++ b/api/routes.py @@ -16,7 +16,8 @@ from api.models import ( ) from api.web_routes import ( get_movies_list, get_tv_series_list, get_series_episodes, get_missing_dates_report, - get_dashboard_stats, update_movie_date, update_episode_date, bulk_update_source + get_dashboard_stats, update_movie_date, update_episode_date, bulk_update_source, + get_movie_date_options, get_episode_date_options ) @@ -1022,9 +1023,10 @@ def register_routes(app, dependencies: dict): @app.get("/api/movies") async def _movies_list(skip: int = 0, limit: int = 100, has_date: Optional[bool] = None, - source_filter: Optional[str] = None, search: Optional[str] = None): + source_filter: Optional[str] = None, search: Optional[str] = None, + imdb_search: Optional[str] = None): """Get paginated movies list with filtering""" - return await get_movies_list(dependencies, skip, limit, has_date, source_filter, search) + return await get_movies_list(dependencies, skip, limit, has_date, source_filter, search, imdb_search) @app.get("/api/series") async def _series_list(skip: int = 0, limit: int = 50, search: Optional[str] = None): @@ -1056,6 +1058,16 @@ def register_routes(app, dependencies: dict): """Bulk update source for movies or episodes""" return await bulk_update_source(dependencies, request.media_type, request.old_source, request.new_source) + @app.get("/api/movies/{imdb_id}/date-options") + async def _movie_date_options(imdb_id: str): + """Get available date options for a movie""" + return await get_movie_date_options(dependencies, imdb_id) + + @app.get("/api/episodes/{imdb_id}/{season}/{episode}/date-options") + async def _episode_date_options(imdb_id: str, season: int, episode: int): + """Get available date options for an episode""" + return await get_episode_date_options(dependencies, imdb_id, season, episode) + # --------------------------- # Static Web Interface # --------------------------- diff --git a/api/web_routes.py b/api/web_routes.py index 0b8db1f..270b810 100644 --- a/api/web_routes.py +++ b/api/web_routes.py @@ -20,7 +20,8 @@ async def get_movies_list(dependencies: dict, limit: int = Query(100, le=1000), has_date: Optional[bool] = Query(None), source_filter: Optional[str] = Query(None), - search: Optional[str] = Query(None)): + search: Optional[str] = Query(None), + imdb_search: Optional[str] = Query(None)): """Get paginated list of movies with filtering options""" db = dependencies["db"] @@ -45,6 +46,10 @@ async def get_movies_list(dependencies: dict, where_conditions.append("(imdb_id LIKE ? OR path LIKE ?)") params.extend([f"%{search}%", f"%{search}%"]) + if imdb_search: + where_conditions.append("imdb_id LIKE ?") + params.append(f"%{imdb_search}%") + where_clause = " AND ".join(where_conditions) if where_conditions else "1=1" # Get total count @@ -431,4 +436,130 @@ async def bulk_update_source(dependencies: dict, media_type: str, old_source: st return { "status": "success", "message": f"Updated {updated_count} {media_type} from source '{old_source}' to '{new_source}'" + } + + +async def get_movie_date_options(dependencies: dict, imdb_id: str): + """Get available date options for a movie (Radarr import, digital release, etc.)""" + db = dependencies["db"] + nfo_manager = dependencies["nfo_manager"] + + # Get current movie data + movie = db.get_movie_dates(imdb_id) + if not movie: + raise HTTPException(status_code=404, detail="Movie not found") + + options = [] + + # Option 1: Current dateadded (if exists and is different from released) + if movie.get('dateadded'): + current_source = movie.get('source', 'Unknown') + current_date = movie['dateadded'] + + # Determine what type of current date this is + if 'radarr' in current_source.lower() and 'import' in current_source.lower(): + label = "Keep Current (Radarr Import Date)" + description = f"Keep using Radarr download/import date: {current_date}" + elif current_source == 'digital_release': + label = "Keep Current (Digital Release)" + description = f"Keep using digital release date: {current_date}" + elif current_source == 'nfo_file_existing': + label = "Keep Current (From Existing NFO)" + description = f"Keep using date from existing NFO file: {current_date}" + else: + label = f"Keep Current ({current_source})" + description = f"Keep using current date from {current_source}: {current_date}" + + options.append({ + "type": "current", + "label": label, + "date": current_date, + "source": current_source, + "description": description + }) + + # Option 2: Released date as digital release (if different from current) + if movie.get('released'): + release_date = f"{movie['released']}T00:00:00" + # Only add if it's different from current dateadded + current_dateadded = movie.get('dateadded', '') + if not current_dateadded or not current_dateadded.startswith(movie['released']): + options.append({ + "type": "digital_release", + "label": "Use Actual Release Date", + "date": release_date, + "source": "digital_release", + "description": f"Use the movie's actual release date: {movie['released']} (instead of download date)" + }) + + # Option 3: Manual entry + options.append({ + "type": "manual", + "label": "Manual Entry", + "date": None, + "source": "manual", + "description": "Enter custom date and time" + }) + + # Try to get additional metadata from external sources + try: + # This would integrate with your existing TMDB/OMDB logic + # For now, we'll use the existing released date as an example + pass + except Exception: + pass + + return { + "imdb_id": imdb_id, + "current_data": movie, + "options": options + } + + +async def get_episode_date_options(dependencies: dict, imdb_id: str, season: int, episode: int): + """Get available date options for an episode""" + db = dependencies["db"] + + # Get current episode data + episode_data = db.get_episode_date(imdb_id, season, episode) + if not episode_data: + raise HTTPException(status_code=404, detail="Episode not found") + + options = [] + + # Option 1: Current dateadded (if exists) + if episode_data.get('dateadded'): + options.append({ + "type": "current", + "label": f"Keep Current ({episode_data.get('source', 'Unknown')})", + "date": episode_data['dateadded'], + "source": episode_data.get('source', 'manual'), + "description": f"Currently using: {episode_data.get('source', 'Unknown')}" + }) + + # Option 2: Aired date + if episode_data.get('aired'): + options.append({ + "type": "airdate", + "label": "Use Air Date", + "date": f"{episode_data['aired']}T20:00:00", # Default to 8 PM + "source": "airdate", + "description": f"Use original air date: {episode_data['aired']}" + }) + + # Option 3: Manual entry + options.append({ + "type": "manual", + "label": "Manual Entry", + "date": None, + "source": "manual", + "description": "Enter custom date and time" + }) + + return { + "imdb_id": imdb_id, + "season": season, + "episode": episode, + "current_data": episode_data, + "options": options } \ No newline at end of file diff --git a/static/css/styles.css b/static/css/styles.css index 3115034..c947b31 100644 --- a/static/css/styles.css +++ b/static/css/styles.css @@ -214,6 +214,19 @@ body { flex-wrap: wrap; } +.search-controls { + display: flex; + gap: 0.5rem; + flex-wrap: wrap; +} + +.filter-controls { + display: flex; + gap: 0.5rem; + align-items: center; + flex-wrap: wrap; +} + .search-box { position: relative; display: flex; @@ -605,6 +618,135 @@ body { } } +/* Smart Fix Modal */ +.smart-fix-options { + display: flex; + flex-direction: column; + gap: 1rem; + margin-bottom: 1rem; +} + +.option-card { + border: 2px solid var(--border-color); + border-radius: 0.5rem; + transition: all 0.2s ease; +} + +.option-card:hover { + border-color: var(--primary-color); + box-shadow: var(--shadow); +} + +.option-label { + display: block; + padding: 1rem; + cursor: pointer; + margin: 0; +} + +.option-label input[type="radio"] { + margin-right: 0.75rem; + margin-top: 0.1rem; + width: auto; +} + +.option-content h4 { + margin: 0 0 0.5rem 0; + color: var(--dark-color); + font-size: 1rem; +} + +.option-content p { + margin: 0 0 0.5rem 0; + color: var(--text-muted); + font-size: 0.9rem; +} + +.option-content small { + color: var(--text-muted); + font-size: 0.8rem; +} + +.manual-date-input { + width: 100% !important; + margin-top: 0.5rem !important; +} + +.option-card input[type="radio"]:checked + .option-content { + color: var(--primary-color); +} + +.option-card:has(input[type="radio"]:checked) { + border-color: var(--primary-color); + background-color: rgba(0, 123, 255, 0.05); +} + +/* Additional badge styles */ +.badge-info { + background-color: #d1ecf1; + color: #0c5460; +} + +/* Enhanced Edit Modal Date Options */ +.date-options { + display: flex; + flex-direction: column; + gap: 0.75rem; + margin-bottom: 1rem; +} + +.date-option-card { + border: 1px solid var(--border-color); + border-radius: 0.375rem; + transition: all 0.2s ease; +} + +.date-option-card:hover { + border-color: var(--primary-color); + box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.1); +} + +.date-option-label { + display: block; + padding: 0.75rem; + cursor: pointer; + margin: 0; +} + +.date-option-label input[type="radio"] { + margin-right: 0.5rem; + margin-top: 0.1rem; + width: auto; +} + +.date-option-content h4 { + margin: 0 0 0.25rem 0; + color: var(--dark-color); + font-size: 0.9rem; + font-weight: 600; +} + +.date-option-content p { + margin: 0 0 0.25rem 0; + color: var(--text-muted); + font-size: 0.8rem; +} + +.date-option-content small { + color: var(--primary-color); + font-size: 0.75rem; + font-weight: 500; +} + +.date-option-card input[type="radio"]:checked + .date-option-content h4 { + color: var(--primary-color); +} + +.date-option-card:has(input[type="radio"]:checked) { + border-color: var(--primary-color); + background-color: rgba(0, 123, 255, 0.03); +} + /* Responsive */ @media (max-width: 768px) { .content-header { diff --git a/static/index.html b/static/index.html index 8a34532..0611250 100644 --- a/static/index.html +++ b/static/index.html @@ -101,21 +101,29 @@

Movies Database

-
@@ -128,13 +136,14 @@ Released Date Added Source + Date Type Video File Actions - Loading movies... + Loading movies... @@ -216,7 +225,7 @@ IMDb ID Released Source - Quick Fix + Smart Fix @@ -239,7 +248,7 @@ IMDb ID Aired Source - Quick Fix + Smart Fix @@ -308,6 +317,24 @@
+ + +