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.