Call refresh_library_cache() after scan completion to immediately publish scanned metadata. Add needs_missing_scan check that only triggers missing scan when German review candidates exist without German tracks. Filter out pending items from missing_german_movies/missing_german_series to prevent showing unscanned files as missing German while background scanner processes them
Add /api/library-status endpoint returning ready/updated_at/error from library_cache with thread-safe lock. Add pollLibrarySync() function to check library status every 5 seconds and reload page when updated_at timestamp changes. Track lastLibrarySync timestamp to detect background sync completion. Save active view to sessionStorage before reload to restore navigation state
Add RAID_REFRESH_SECONDS/IO_REFRESH_SECONDS/GPU_REFRESH_SECONDS environment variables with default 5 seconds and minimum 2 seconds. Add graphics_cache_lock and graphics_cache global for thread-safe GPU data access. Add io/io_at fields to datastore_cache. Extract refresh_io_status() to update I/O pressure cache. Add refresh_gpu_status() to update graphics_cache. Implement hardware
Add SYNC_INTERVAL_SECONDS environment variable with default 1800 (30 minutes). Add library_cache global dict with rows/series/updated_at/error/ready fields and library_cache_lock for thread-safe access. Extract refresh_library_cache() function to update Radarr/Sonarr data with error handling that preserves last good snapshot during outages. Add background_library_sync() daemon
Add graphics_process_log_state global to track GPU process changes. Query nvidia-smi pmon with 1-count sample to detect video encode/decode processes missed by compute-apps query. Parse pmon output for SM/ENC/DEC utilization percentages and process types. Merge pmon results with compute-apps by PID, preferring pmon data when available. Log GPU process detection with PID/name
Add graphics_log_state global to track GPU query status and prevent duplicate log messages. Log warning with error_summary() when nvidia-smi is unavailable or returns non-zero exit code. Log info message when GPU status becomes available with GPU count and binary path. Track signature tuples for unavailable/failed/ok states including GPU index/name/temperature/utilization.
Add graphics_snapshot() function to query GPU details using nvidia-smi with 5s timeout. Parse GPU metrics including model, driver, UUID, serial, temperature, utilization, VRAM, power, clocks, and compute processes. Add NVIDIA_SMI_BIN environment variable with default "nvidia-smi". Add /api/graphics endpoint returning GPU data with error handling. Add Graphics navigation tab with purple expansion-card icon
Add raid_refresh_lock to prevent concurrent RAID refresh operations. Extract refresh_raid_status() function with non-blocking lock acquisition using acquire(blocking=False). Update datastore_snapshot() to spawn background thread for RAID refresh when cache is stale but return immediately with cached data. Remove offline navigation fallback from service worker to prevent masking backend errors. Bump service worker cache version to v7
Add datastore_refresh_lock to prevent concurrent refresh operations. Extract refresh_datastore_storage() function with non-blocking lock acquisition using acquire(blocking=False). Update datastore_snapshot() to spawn background thread for refresh when cache is stale but return immediately with cached data. Add offline fallback HTML page to service worker for navigate requests with 503 status for
Add SCANNER_VERSION constant set to 2 and include in run_ffprobe() output. Create language_from_text() helper to infer language from track titles using token matching with German/English/Japanese/Korean/French/Spanish/Italian aliases. Apply language_from_text() to subtitle streams when ffprobe reports "und" language tag by checking title field. Update cached() to validate scanner_version matches
Add "missing" job state to jobs dict with idle/total/done/error tracking. Update start_scan() to handle "missing" source by filtering radarr_rows() and sonarr_groups() for is_german_review_candidate() entries without has_german_track(). Skip cache deletion for missing-German scan in api_rescan() with comment explaining cache preservation. Add "Nur Ohne Deutsch" option to scanSource select
Add Italian/Portuguese/Korean/Chinese/Dutch/Russian to patterns list with standard/ISO 639-2 codes (ita/por/pt br/kor/chi/zho/nld/ned/rus). Enhance German patterns with " ger "/" deu " tokens and French with " français "/" fre " variants. Add corresponding language codes to codes dict (it/pt/ko/zh/nl/ru). Format patterns list with multi-line structure for readability
Add smart_serial() function with smartctl -i command execution, fallback to -d sat mode, and Serial Number: field regex extraction with WWN/0x prefix filtering to prefer physical serial over logical identifiers. Add serial_futures dict with service_check_executor.submit() calls for parallel serial reads alongside smart_futures/temperature_futures. Update raid_status() disk
Add io_pressure() function to parse /proc/pressure/io with line splitting, key-value extraction from some/full metrics, and OSError/ValueError exception handling returning available:False on failure. Add io_pressure() call to datastore_snapshot() return dict. Add DOMContentLoaded script to create #ioPressurePanel section with datastore-panel/io-pressure-panel classes, innerHTML with I/O-
Swap Temperature_Celsius to first position in ordered list before Current Drive Temperature/Drive Temperature/Temperature: patterns. Add Temperature_Celsius.*-\s*(-?\d{1,3}) regex to extract raw value from attribute line with 0-150 range validation before falling back to explicit unit pattern matching to improve accuracy when both formatted and raw temperature values are present
Update temperature line matching to first search for Current Drive Temperature/Drive Temperature/Temperature: patterns, then append Temperature_Celsius lines, before falling back to generic temperature/airflow keywords. Swap smartctl -x -d sat command before -A -d sat in fallback chain to improve attribute detection on SATA drives behind
Reorder temperature line matching to first search for Temperature_Celsius/Drive_Temperature/Current Drive Temperature attributes before falling back to generic temperature/airflow keywords. Add ordered list construction with preferred patterns first, then append remaining temperature lines, to ensure physical drive temperature is selected over airflow sensor when both are present in
Move -d sat variants of -A and -x commands to front of fallback chain before non-sat equivalents in smart_temperature() function to improve compatibility with SATA drives behind USB/RAID controllers
Replace regex pattern matching with extract() helper that iterates through output lines, filters for temperature/airflow keywords, and extracts values using explicit unit patterns (°C/Celsius/degrees C) with 0-150 range validation or fallback to last plausible number in line. Add smartctl -x/-x -d sat commands to fallback chain after -A/-A -d sat attempts with early return on first successful
Add smart_temperature() function with smartctl -A command execution, fallback to -d sat mode, and regex patterns for Temperature_Celsius/Airflow_Temperature_Cel/Drive_Temperature/Current Drive Temperature attributes plus Temperature: field parsing with 1-3 digit capture and °C formatting. Add temperature_futures dict with service_check_executor.submit() calls for parallel temperature reads alongside smart_futures. Add disk["
Add error_summary() function to format exceptions as single-line log messages with 240-char limit and special handling for requests.RequestException as "Dienst nicht erreichbar". Replace log.exception() calls with log.error() using error_summary() across service_monitor, scan_datastore_storage, sab_downloads, scan_one, start_scan, index, downloads, system, and datastore endpoints. Update user-facing error messages to German "momentan nicht verfügbar/
Add /sw.js route with send_from_directory to serve service worker from root scope with Service-Worker-Allowed:/ and Cache-Control:no-cache headers. Add navigator.serviceWorker.register() script to index.html with load event listener and scope:/ parameter. Update service worker cache to v4 with media-mark-192.svg/media-mark-512.svg additions to SHELL array.
Update manifest.json icons
Add datastore_cache raid/raid_at fields for RAID status caching with 60-second fallback window. Extract smart_status() function from raid_status() to enable parallel execution. Add ThreadPoolExecutor submission for SMART checks across all RAID disks with concurrent futures. Update SMART logging to check "PASSED" status explicitly instead of regex match presence. Add stale/warning fields to datastore_snapshot() when fresh
Add os.getloadavg() to system_metrics() with (0,0,0) fallback for AttributeError/OSError. Add /proc/uptime parsing for uptime_seconds with float conversion and 0 fallback. Add /proc process counting by iterating numeric entries with OSError exception handling. Add load/uptime_seconds/processes fields to /api/system response with rounded values.
Add DOMContentLoaded script to inject #
Add LOG_FILE and LOG_RETENTION_HOURS environment variables to .env.example with defaults /data/media-max.log and 6 hours. Install TimedRotatingFileHandler with hourly rotation, 1 backup, UTF-8 encoding, and UTC timestamps. Add OSError exception handling with warning log when file logging unavailable. Add warn_on_nonzero parameter to _read_command() with default True and disable for smartctl -H calls to suppress expected
Install udev package and mount /run/udev:/host-run-udev:ro for udev by-id symlink access. Add raid_log_state global to track RAID status changes and hardware_log_once set to prevent duplicate hardware warnings. Update scan_datastore_storage() with info/error logging for scan lifecycle and disk usage. Add _read_command() debug/warning/error logging for all subprocess calls with command text
Add HOST_SYS_PATH=/host-sys to .env.example and app.py config with /host-sys default. Update _device_serial() to check HOST_SYS_PATH/class/block and HOST_SYS_PATH/block before fallback /sys paths for serial reads. Update raid_status() SMART regex to match both "SMART overall-health self-assessment test result" and "SMART Health Status" with case-insensitive flag for NVMe/SSD compatibility. Add /
Add _device_serial() to read disk serials from /sys/class/block/{name}/device/serial and /sys/block/{name}/device/serial when lsblk cannot expose them in Docker containers. Update raid_status() to use sysfs fallback before defaulting to "—" for missing serials. Add .raid-disks 2-column grid with 6px gap, .raid-disk 7px/9px padding, .raid-disk small 1px top margin, and .raid-smart 85% opacity. Add mobile
Add format_transfer_rate() to convert mdstat rates (e.g., 133628K/sec) into readable values like "130.5 MB/s" using 1024-based units. Add format_remaining_time() to convert mdstat durations (e.g., 450.1min) into compact German format like "7 Std. 30 Min." with day/hour/minute components. Update raid_status() to parse member devices directly from array_line in /proc/mdstat to avoid cross
Add scan_datastore_storage() to walk DATASTORE_PATH and categorize media by directory structure (movies/series/anime/kdrama/downloads/other) with size/file counts. Add raid_status() to parse /proc/mdstat and mdadm --detail for RAID level, active/failed devices, and recovery progress. Add /api/datastore endpoint with 15-minute cache for storage scans and live RAID updates. Install mdadm/util-linux/
Update project name from "Radarr Language Dashboard v2" to "Media Max" in README.md, docker-compose.yml service/container names, app.py logger name and service definition, manifest.json name/short_name/description, and templates/index.html title and header elements. Update docker exec command example in README to use new container name.
Add showSeasonZero checkbox in settings panel with toggle styling (42x23px switch, green when active). Implement applySeasonZeroPreference() to filter S00E episodes via .season-zero-hidden class and hide empty series with .season-zero-empty. Update missing count in nav badge and stats to exclude hidden season zero episodes. Add dynamic hint text toggle between "eingeblendet"/"ausgeblendet". Remove season zero exclusion from is_german_review_candidate() in app.py to
Add tag fetching from Sonarr API and category_for() function to classify series based on normalized tags (anime, kdrama, standard). Parse tag labels/names into normalized strings removing non-alphanumeric characters for matching. Add category and category_label fields to series groups.
Update index route to build series_categories list grouping series by category key (anime/Anime, kdrama/K-Dramen, standard/Standard) and pass
Add SERVICE_DEFINITIONS list with Radarr, Sonarr, SABnzbd, Jellyfin, Seerr, Prowlarr, Easynews as Indexer, qBittorrent, Bazarr, Lingarr, LibreTranslate, Sonarr-Prowlarr Proxy, Radarr-Prowlarr Proxy, and Dashboard. Add check_service() to perform HTTP/API health checks with configurable timeout. Add refresh_services() to run checks in parallel using service_check_executor ThreadPoolExecutor with 16 workers.
Update media_row() to combine embedded subtitle_languages from ffprobe with external subtitle files detected via external_subtitle_languages(). Apply unique_langs() to deduplicate language codes when local_path is available, ensuring both .mkv internal subs and external .srt/.ass files appear in the subtitle language list.
Add EXTERNAL_SUBTITLE_EXTENSIONS set with common subtitle formats (.srt, .ass, .ssa, .vtt, .sub, .idx, .sup). Add external_subtitle_files() to glob subtitle files matching media stem and external_subtitle_languages() to parse language codes from filenames (de/deu/ger/german/deutsch, en/eng/english, fr/fra/fre/french/französisch, es/spa/spanish/spanisch, it/ita/italian/italienisch).
Update run_ffprobe() to merge external subtitle
Add scan_executor ThreadPoolExecutor with 4 workers for parallel file scanning. Import as_completed from concurrent.futures to process scan results. Replace sequential scan_one() loop with parallel futures submission and result collection using as_completed().
Update /api/rescan endpoint to accept "all" source parameter for scanning both Radarr and Sonarr simultaneously. Fix cache deletion
Add dashboard_stats dictionary to index() route calculating movie/episode totals, available files, missing items, and downloading counts. Pass stats to template for dashboard insights display.
Add dashboard-insights CSS grid with 4 insight cards showing media availability (movies/episodes), monitoring status, and live updates. Each card has color-coded icon with
Add German comment explaining that Filme and Serien share the same host storage (/nesflix) and are made visible in the container via media mounts. Update mount_paths list to replace "Daten" label with "Medien" and combine Filme/Serien paths under single "Medien" label. Add dashboard-view CSS class with flex layout, min-height constraints, and increased disk-list gap for improved vertical
Add system_metrics() function to read CPU usage from /proc/stat with delta calculation, memory stats from /proc/meminfo, and disk usage for System/Daten/Filme/Serien mounts with device deduplication. Add /api/system endpoint returning metrics JSON with error handling.
Add dashboard view as default tab with hero section, 4-card overview grid showing movie/series/missing/download counts, system
Add is_german_review_candidate() helper function to filter media that exists locally or is currently being downloaded, excluding season 0 (specials) episodes. Apply filter to missing_german_movies and missing_german_series lists to show only actionable items. Update tab description text from "Kein deutsches Audio und keine deutschen Untertitel" to "Vorhanden oder wird gerade geladen · Staffel
Add parse_size_bytes() and format_bytes() helper functions to convert and format file sizes. Calculate total remaining bytes from queue and include active_count, history_count, remaining_bytes, and formatted remaining in downloads API response. Update error responses to include new fields.
Add media-mark.svg favicon with gradient background, golden lines, and green checkmark. Replace text logo with inline
Add new navigation tab showing count of movies and episodes without German tracks. Implement has_german_track() helper to check for German audio or subtitles. Filter movies and series to create missing_german_movies and missing_german_series lists passed to template. Add dedicated view section with tables for movies and series lacking German content, including empty state message. Update navigation translation logic
Add visual separators between seasons in series episode tables. Extract season number from episode data and insert divider rows with "Staffel N" labels when season changes. Style dividers with dark background and subtle borders to improve readability of long episode lists.
Replace exact title matching with token-based fuzzy matching that requires 75% of significant tokens (3+ chars) to match. Add "downloading" class to state column and apply purple badge styling to quality column for downloading items. Update download refresh to trigger markDownloading() and initialize download markers on page load.
Add "pending" flag to cached() error response for missing files to enable download status detection. Update docker-compose to always mount series volume with fallback default path instead of requiring manual uncomment. Update README to clarify that SERIES_MEDIA_VOLUME must point to actual host path when Sonarr is enabled.
Add SABnzbd integration to display active and completed downloads with progress tracking, speed monitoring, and automatic language detection from release names. Downloads are matched against Radarr/Sonarr queues to identify source application. Add new Downloads tab in navigation, API endpoint for queue/history data, and auto-refresh every 4 seconds. Include configuration for SAB_URL and SAB_API_KEY in docker-compose and
Add Sonarr integration alongside existing Radarr functionality. Implement background ffprobe scanning with ThreadPoolExecutor, progress tracking API, and separate navigation for movies/series. Series are grouped by show with collapsible episodes. Reduce Gunicorn workers to 1, add scan status endpoint, and update README with Sonarr configuration instructions.
Add a Flask-based dashboard for monitoring audio/subtitle languages in Radarr media files. Includes ffprobe integration for media analysis, SQLite caching, path mapping between Radarr and host filesystems, and a responsive web UI with filtering and statistics.