From a6492af5c564997b6bb389a8e5d0f43e8d819a80 Mon Sep 17 00:00:00 2001 From: mhdzumair Date: Wed, 15 Jan 2025 13:06:36 +0530 Subject: [PATCH] Refactor TMDB data scraper and enhance Import UI with styling. Enhanced TMDB API scraper with better episode and year handling, streamlined year match logic, and improved metadata updates. CSS updates provide a more polished UI with better hover effects, spacing, and theming adjustments for a consistent dark mode appearance. --- db/crud.py | 7 + resources/css/styles.css | 352 +++++++++++++++++++++++++++- resources/html/scraper.html | 410 ++++++++++++++++++--------------- resources/js/scraperControl.js | 225 ++++++++++++++++-- scrapers/imdb_data.py | 2 + scrapers/routes.py | 11 +- scrapers/scraper_tasks.py | 7 +- scrapers/tmdb_data.py | 237 +++++++------------ 8 files changed, 875 insertions(+), 376 deletions(-) diff --git a/db/crud.py b/db/crud.py index 5a00138..beaf5e0 100644 --- a/db/crud.py +++ b/db/crud.py @@ -809,6 +809,8 @@ async def get_tv_meta(meta_id: str): async def get_existing_metadata( metadata: dict, model: Type[MediaFusionMovieMetaData | MediaFusionSeriesMetaData] ) -> Optional[MediaFusionMovieMetaData | MediaFusionSeriesMetaData]: + if metadata.get("id"): + return await model.get(metadata["id"]) title = metadata["title"] year = metadata.get("year") if isinstance(year, str): @@ -1590,6 +1592,11 @@ async def update_metadata(imdb_ids: list[str], metadata_type: str): ) # Get existing metadata to preserve values existing_metadata = await meta_class.get(meta_id) + if not existing_metadata: + logging.warning( + f"Metadata not found for {metadata_type} {meta_id}. Skipping update." + ) + continue # Merge new data with existing data, preserving existing values when new ones are None/empty update_data = { diff --git a/resources/css/styles.css b/resources/css/styles.css index 8881a94..c95904a 100644 --- a/resources/css/styles.css +++ b/resources/css/styles.css @@ -11,6 +11,7 @@ body, html { background-position: center center; background-repeat: no-repeat; } + .mode-switch { background: rgba(20, 20, 35, 0.7); padding: 1.5rem; @@ -51,16 +52,19 @@ body, html { background: rgba(74, 71, 163, 0.4); transform: translateY(-2px); } + .mode-btn:focus-visible { outline: 2px solid #fff; outline-offset: 2px; } + .mode-btn[aria-pressed="true"] { background: #4a47a3; color: white; border-color: #4a47a3; box-shadow: 0 4px 12px rgba(74, 71, 163, 0.3); } + .mode-btn.active { background: #4a47a3; color: white; @@ -100,18 +104,136 @@ body, html { } .section-container { - margin-bottom: 1rem; - padding: 1rem; - background: rgba(0, 0, 0, 0.37); - border-radius: 8px; + padding: 1.5rem; + margin-bottom: 1.5rem; + background: rgba(20, 20, 35, 0.85); + border-radius: 12px; transition: margin-bottom 0.3s ease, padding 0.3s ease; } +.section-container .card { + background: rgba(30, 30, 50, 0.9); + border: 1px solid rgba(74, 71, 163, 0.3); + margin-bottom: 1.5rem; +} + +.section-container .card-header { + background: rgba(74, 71, 163, 0.2); + border-bottom: 1px solid rgba(74, 71, 163, 0.3); + padding: 1rem 1.5rem; +} + +.section-container .card-header h5 { + color: #ffffff; /* Bright white for headers */ + font-weight: 500; + margin: 0; +} + +.section-container .card-body { + padding: 1.5rem; +} + .section-header { color: #E0E0E0; margin-bottom: 0.5rem; } +.list-group-item-action { + transition: all 0.2s ease; + border: 1px solid rgba(74, 71, 163, 0.2); + background: rgba(30, 30, 50, 0.95); /* Slightly more opaque */ + color: #ffffff; /* Bright white for main text */ +} + +.list-group-item-action:hover { + transform: translateY(-2px); + border-color: rgba(74, 71, 163, 0.4); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); + background: rgba(40, 40, 60, 0.98); /* Even more opaque on hover */ +} + +/* Title and year */ +.list-group-item h5 { + color: #ffffff; + font-weight: 500; +} + +.list-group-item h5 .text-muted { + color: #bdbdbd !important; /* Lighter gray for year */ +} + +/* Description and other text */ +.list-group-item .text-muted { + color: #bdbdbd !important; /* Lighter gray for better readability */ +} + +/* Meta information */ +.list-group-item .small, +.list-group-item small { + color: #e0e0e0; /* Light gray for small text */ +} + +/* Genre badges */ +.badge.bg-primary { + background-color: rgba(74, 71, 163, 0.3) !important; + color: #ffffff !important; + border: 1px solid rgba(74, 71, 163, 0.5); +} + +/* Icons */ +.list-group-item i { + color: #4a47a3; /* Accent color for icons */ +} + +/* Rating */ +.badge.bg-secondary { + background-color: rgba(158, 158, 158, 0.3) !important; + color: #e0e0e0 !important; +} + +/* Meta sections */ +.list-group-item .d-flex.align-items-center { + color: #e0e0e0; /* Light gray for meta information */ +} + +/* Content type labels (Comedy, Romance, etc.) */ +.genre-tag { + background: rgba(74, 71, 163, 0.2); + color: #ffffff; + padding: 0.25rem 0.75rem; + border-radius: 4px; + font-size: 0.9rem; + margin-right: 0.5rem; + border: 1px solid rgba(74, 71, 163, 0.3); +} + +/* IMDb rating */ +.text-warning { + color: #ffd700 !important; /* Brighter yellow for rating stars */ +} + +.list-group-item img { + transition: transform 0.2s ease; +} + +.list-group-item:hover img { + transform: scale(1.05); +} + +.badge { + font-weight: 500; + padding: 0.5em 0.8em; +} + +.gap-2 { + gap: 0.5rem !important; +} + +.gap-3 { + gap: 1rem !important; +} + + .section-divider { border: 0; height: 2px; @@ -126,12 +248,14 @@ body, html { transform: translateY(-10px); transition: all 0.3s ease-in-out; } + @media (prefers-reduced-motion: reduce) { .pro-mode-section { transform: none; transition: opacity 0.3s ease-in-out; } } + .pro-mode-section[style*="display: block"] { opacity: 1; transform: translateY(0); @@ -220,6 +344,7 @@ input[type="text"]:focus, input[type="password"]:focus, select.form-control:focu display: block; align-items: center; border: 2px solid transparent; + margin-top: 1rem; margin-bottom: 0.5rem; padding: 0.2rem; border-radius: 5px; @@ -250,6 +375,7 @@ input[type="text"]:focus, input[type="password"]:focus, select.form-control:focu display: flex; align-items: center; gap: 1rem; + color: #e0e0e0; min-height: 36px; /* Minimum touch target size */ } @@ -257,6 +383,11 @@ input[type="text"]:focus, input[type="password"]:focus, select.form-control:focu content: none; /* Remove the round indicator */ } +.form-check-input:checked { + background-color: #4a47a3; + border-color: #4a47a3; +} + .form-check-input:checked + .form-check-label { background: #4a47a3; border-color: #4a47a3; @@ -274,6 +405,10 @@ input[type="text"]:focus, input[type="password"]:focus, select.form-control:focu color: white; } +.form-check-input:checked ~ .form-check-label { + color: #ffffff; +} + /* Style for disabled checkboxes */ .form-check.disabled-checkbox { opacity: 0.5; @@ -288,6 +423,11 @@ input[type="text"]:focus, input[type="password"]:focus, select.form-control:focu pointer-events: none; } +.form-label { + color: #e0e0e0; + font-weight: 500; + margin-bottom: 0.5rem; +} .form-control { display: block; @@ -307,6 +447,19 @@ input[type="text"]:focus, input[type="password"]:focus, select.form-control:focu transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out; } + +.form-control, .form-select { + background: rgba(255, 255, 255, 0.9); /* More opaque white background */ + border: 1px solid rgba(74, 71, 163, 0.3); + color: #000; /* Black text for better contrast */ +} + +.form-control:focus, .form-select:focus { + background: #ffffff; + border-color: #4a47a3; + box-shadow: 0 0 0 0.25rem rgba(74, 71, 163, 0.25); +} + /* Styling for the range slider */ .form-range { -webkit-appearance: none; /* Override default look for Chrome, Safari */ @@ -433,6 +586,12 @@ input[type="text"]:focus, input[type="password"]:focus, select.form-control:focu margin-bottom: 10px; } +.alert-info { + background: rgba(74, 71, 163, 0.15); + border-color: rgba(74, 71, 163, 0.3); + color: #e0e0e0; +} + .loading-overlay { position: fixed; top: 0; @@ -480,16 +639,16 @@ input[type="text"]:focus, input[type="password"]:focus, select.form-control:focu } .configured-field { - background-color: #f8f9fa; + background-color: #f8f9fa; } .reset-config-btn { - margin-left: 0.5rem; + margin-left: 0.5rem; } .input-group .reset-config-btn { - border-top-left-radius: 0; - border-bottom-left-radius: 0; + border-top-left-radius: 0; + border-bottom-left-radius: 0; } .sort-item { @@ -514,6 +673,183 @@ input[type="text"]:focus, input[type="password"]:focus, select.form-control:focu margin-bottom: 0.75rem; } +.advanced-toggle { + background: rgba(74, 71, 163, 0.15); + padding: 0.75rem 1rem; + border-radius: 8px; + border: 1px solid rgba(74, 71, 163, 0.2); + color: #e0e0e0; + cursor: pointer; + display: flex; + align-items: center; + gap: 0.5rem; + margin: 1rem 0; + transition: all 0.3s ease; +} + +.advanced-toggle:hover { + background: rgba(74, 71, 163, 0.25); +} + +.advanced-toggle i { + transition: transform 0.3s ease; + margin-right: 0.5rem; +} + +.advanced-toggle.active i { + transform: rotate(180deg); +} + +.advanced-section { + display: none; + opacity: 0; + transform: translateY(-10px); + transition: all 0.3s ease; +} + +.advanced-section.show { + display: block; + opacity: 1; + transform: translateY(0); +} + +.parsed-value { + color: #4a47a3; + font-size: 0.9rem; + margin-top: 0.25rem; +} + +.technical-specs-basic { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: 1rem; + margin-bottom: 1.5rem; +} + +.technical-specs-basic .spec-item { + background: rgba(74, 71, 163, 0.1); + padding: 0.75rem; + border-radius: 6px; + display: flex; + align-items: center; + gap: 0.5rem; +} + +.spec-item { + background: rgba(74, 71, 163, 0.15); + padding: 1rem; + border-radius: 8px; + border: 1px solid rgba(74, 71, 163, 0.2); +} + +.spec-item i { + color: #4a47a3; +} + + +.spec-label { + color: #e0e0e0; + font-size: 0.9rem; + margin-bottom: 0.25rem; +} + +.spec-value { + color: #ffffff; + font-weight: 500; +} + + +.not-available { + color: #6c757d; + font-style: italic; +} + +/* Catalog Section Styles */ +.catalogs-section { + border-top: 1px solid rgba(74, 71, 163, 0.2); + padding-top: 1.5rem; +} + +.section-title { + color: #4a47a3; + margin-bottom: 1rem; + font-weight: 500; +} + +.catalog-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); + gap: 1rem; + margin-top: 1rem; +} + +.catalog-item { + background: rgba(74, 71, 163, 0.1); + border-radius: 6px; + padding: 0.5rem; + transition: all 0.3s ease; +} + +.catalog-item:hover { + background: rgba(74, 71, 163, 0.2); + transform: translateY(-2px); +} + +.catalog-item .form-check { + margin: 0; + padding: 0.25rem; +} + +.catalog-group { + margin-bottom: 1.5rem; +} + +.catalog-group .alert { + margin-bottom: 1rem; + border-left: 4px solid #4a47a3; +} + + +/* Text utility classes for dark theme */ +.text-muted { + color: #9e9e9e !important; /* Lighter gray for better visibility */ +} + +/* Other text utility classes that might need adjustment */ +.text-secondary { + color: #b0b0b0 !important; +} + +.text-body-secondary { + color: #a0a0a0 !important; +} + +/* Form text and help text */ +.form-text { + color: #9e9e9e !important; +} + +/* Subtitle styling */ +.card-subtitle { + color: #b0b0b0 !important; +} + +/* Description text */ +.description-text { + color: #9e9e9e !important; +} + +/* Optional help text */ +small.text-muted, +.small.text-muted { + color: #9e9e9e !important; +} + +/* Alert text */ +.alert .text-muted { + color: #b0b0b0 !important; +} + @media (max-width: 576px) { .sort-direction-toggle { min-width: auto; diff --git a/resources/html/scraper.html b/resources/html/scraper.html index 0638c8c..ddc8a0e 100644 --- a/resources/html/scraper.html +++ b/resources/html/scraper.html @@ -109,49 +109,53 @@ - +