- Fix 55 test failures caused by missing request contexts and incorrect
session_transaction() usage across 8 test files
- Fix ruff import sorting errors and unused imports
- Fix 122 type errors: rename method override parameters to match base
classes, add None guards for fetchone()/datetime, widen dict type
annotations, add type: ignore for SQLAlchemy stub limitations
- Add [tool.ty.rules] config to suppress unsupported-base warnings
- Fix _ variable shadowing gettext in wizard routes
- Add noqa: ARG002 for unused method arguments required by base class
Jellyfin and Emby collectors were recording RunTimeTicks (total file
runtime) as the session duration, causing severe overestimation when
users stopped partway through long titles.
- JellyfinCollector._emit_session_event: on session_end, use position_ms
(last known playback position) as duration_ms; fall back to
raw_duration_ms only when position_ms is unavailable or zero.
- EmbyCollector._emit_session_event: identical fix (shared API shape).
- JellyfinHistoricalImporter._process_item: for partially-watched items
(UserData.Played == false) use PlaybackPositionTicks; keep RunTimeTicks
only for fully-played items where position has already been reset.
- historical_duration_source metadata field now accurately reflects
which source was used (runtime_ticks, playback_position_ticks, or
runtime_ticks_fallback).
Plex was already correct via elapsed-time tracking in SessionManager.
This fixes a critical issue where Gunicorn workers would fail to start
after upgrading to v2025.11.0, causing containers to show as unhealthy
with only the uv wrapper process running and no actual workers.
Root Cause:
-----------
In v2025.11.0, library scanning and session recovery were added to the
create_app() function, which runs during EVERY app creation including:
1. During 'flask db upgrade' (migrations)
2. During Gunicorn master when_ready() hook
3. During each Gunicorn worker spawn
The migration 20251103_properly_fix_foreign_keys recreates 4 database
tables with CASCADE foreign keys using raw SQL. This holds exclusive
database locks during table recreation.
When library scanning and session recovery try to query these tables
during migration, they hit database locks, creating a race condition
that causes workers to timeout and crash during startup.
Fix:
----
- Skip library scanning during migrations (FLASK_SKIP_SCHEDULER=true)
- Skip activity monitoring/session recovery during migrations
- Make Gunicorn log level configurable (GUNICORN_LOG_LEVEL env var)
- Add worker lifecycle hooks for better crash debugging
- Increase healthcheck start period from 10s to 60s
- Increase Gunicorn worker timeout from 30s to 120s
Testing:
--------
- Verified app starts successfully with FLASK_SKIP_SCHEDULER=true
- Verified library scanning runs normally without the flag
- Confirmed 0.38s startup during migrations vs 1.61s normal startup
Closes#976
fix: correct key for transcoding info in admin routes
feat: enhance Jellyfin client to extract additional session and media details
fix: update template to reflect changes in transcoding info structure
chore: update submodule reference for plus
- Moved utility functions for datetime parsing, tick conversion, and session building from `historical_data.py` to a new module `utils.py`.
- Deleted the `historical_data.py` file as its functionality is now encapsulated in the new utility module.
- Updated the `build_activity_session` function to utilize the new utility functions for improved readability and maintainability.
- Redesigned the Activity Settings page for improved user experience, including better organization of sections and updated alert messages.
- Added functionality to import historical data from Jellyfin and Emby servers, allowing users to specify the number of days back and a result limit for imports.
- Updated the HistoricalDataService to support importing history from Jellyfin and Emby, including detailed logging and error handling.
- Improved the UI for historical data import, including form validation and user feedback during the import process.
- Cleaned up completed historical import jobs from the database to prevent indefinite persistence.
- Introduced the HistoricalImportJob model to track historical data import jobs.
- Implemented asynchronous job processing for importing historical activity data from media servers.
- Enhanced the activity settings page to allow users to specify the number of days back for historical imports.
- Added a new route to display recent historical import jobs.
- Updated the import_historical_activity function to create and manage import jobs.
- Improved UI components for displaying success and error messages related to historical imports.
- Added migration script to create the historical_import_job table in the database.
- Added `identity_resolution.py` for resolving Wizarr users and identities.
- Created `ingestion.py` to handle recording and updating activity events.
- Introduced `maintenance.py` for cleanup and session management tasks.
- Developed `queries.py` for read-oriented operations on activity sessions.
- Implemented background tasks in `activity.py` for scheduled maintenance.
- Added tests for activity services and blueprint to ensure functionality.