Skip to content

Releases: Serph91P/MediaCurator

Development Build 4.1.1-dev

28 Apr 06:59
af8c952

Choose a tag to compare

Pre-release

What's Changed in 4.1.1-dev

Bug Fixes

  • docker: Pin PGDATA so postgres:18 reuses existing data volume

Other Changes

  • Merge pull request #57 from Serph91P/fix/auth-persistence-and-delete-reliability

fix(docker): pin PGDATA so postgres:18 reuses existing data volume


Docker Images

This release is available as a Docker image for amd64 architecture:

Pull the image:

# Specific version
docker pull ghcr.io/Serph91P/mediacurator:4.1.1-dev

# Or latest stable (main branch)
docker pull ghcr.io/Serph91P/mediacurator:latest

# Or development (develop branch)
docker pull ghcr.io/Serph91P/mediacurator:dev

Run with Docker Compose:

# Download docker-compose.yml
curl -O https://raw.githubusercontent.com/Serph91P/MediaCurator/main/docker-compose.yml

# Start services
docker compose up -d

Registry Information

Property Value
Registry GitHub Container Registry (ghcr.io)
Image ghcr.io/Serph91P/mediacurator
Version 4.1.1-dev
Architecture linux/amd64

Note: ARM64 builds are not currently provided. Open a feature request if you need ARM support.

Documentation

See the README.md for full configuration options.

Development Build 4.1.0-dev

27 Apr 16:02
99c2114

Choose a tag to compare

Pre-release

What's Changed in 4.1.0-dev

Bug Fixes

  • auth: Persist secret key across restarts to keep sessions valid
  • sync: Make Sonarr/Radarr deletes two-phase and observable

Features

  • ui: Warn user when refresh fails because no users exist

Other Changes

  • Merge pull request #56 from Serph91P/fix/auth-persistence-and-delete-reliability

Fix/auth persistence and delete reliability


Docker Images

This release is available as a Docker image for amd64 architecture:

Pull the image:

# Specific version
docker pull ghcr.io/Serph91P/mediacurator:4.1.0-dev

# Or latest stable (main branch)
docker pull ghcr.io/Serph91P/mediacurator:latest

# Or development (develop branch)
docker pull ghcr.io/Serph91P/mediacurator:dev

Run with Docker Compose:

# Download docker-compose.yml
curl -O https://raw.githubusercontent.com/Serph91P/MediaCurator/main/docker-compose.yml

# Start services
docker compose up -d

Registry Information

Property Value
Registry GitHub Container Registry (ghcr.io)
Image ghcr.io/Serph91P/mediacurator
Version 4.1.0-dev
Architecture linux/amd64

Note: ARM64 builds are not currently provided. Open a feature request if you need ARM support.

Documentation

See the README.md for full configuration options.

Development Build 4.0.1-dev

27 Apr 15:52
e8c047d

Choose a tag to compare

Pre-release

What's Changed in 4.0.1-dev

Other Changes

  • Develop (#55)
  • feat: Complete Phase 2 - Users, Activity & Library Detail Views
  • Add PlaybackActivity model for detailed playback session tracking
  • Add activity API routes (/api/activity/) with list, stats, active sessions
  • Add users API routes (/api/users/) with list, detail, activity endpoints
  • Extend Emby sync with _sync_active_sessions() for real-time session tracking
  • Add Users.tsx page with search, pagination, user stats
  • Add UserDetail.tsx page with Overview/Activity tabs and time-based stats
  • Add Activity.tsx page with global activity log, active sessions, stats cards
  • Add LibraryDetail.tsx with Overview/Media/Activity tabs
  • Extend libraries API with /details, /media, /activity endpoints
  • Update navigation with Users and Activity menu items
  • Library cards now link to detail view

Completes Phase 2 of PLANNED_FEATURES.md roadmap (Jellystat-style features)

  • feat: Add PostgreSQL support and fix sync issues

Database:

  • Add PostgreSQL support via POSTGRES_* environment variables
  • Add asyncpg driver to requirements
  • Create docker-compose.postgres.yml for PostgreSQL setup
  • Keep SQLite as default for simple deployments
  • Add connection pooling for PostgreSQL

Bug Fixes:

  • Fix MediaItem.parent_id AttributeError by using series_id (external_id)
  • Add parent_id column to MediaItem model for future use
  • Fix Users API to fallback to UserWatchHistory when PlaybackActivity is empty
  • Fix deprecation warning: regex -> pattern in Query parameters
  • Remove 'Jellystat-style' comments from codebase

Improvements:

  • Sync jobs now visible in Jobs view with execution logs
  • Manual sync shows progress/errors in Jobs history
  • Users page shows last watched from UserWatchHistory fallback
  • chore: Update PostgreSQL to version 18 (latest stable)

  • fix: Add PostgreSQL support to database migrations

  • Add column_exists() helper for SQLite/PostgreSQL compatibility
  • Add table_exists() helper for SQLite/PostgreSQL compatibility
  • Use information_schema for PostgreSQL column/table checks
  • Use pragma_table_info for SQLite column checks
  • Add IF NOT EXISTS for PostgreSQL ALTER TABLE commands
  • Use SERIAL PRIMARY KEY for PostgreSQL auto-increment
  • chore: Remove ARM64 build to speed up CI
  • Build only linux/amd64 for faster builds
  • Remove QEMU setup (not needed without cross-platform builds)
  • Update release notes to reflect single architecture
  • Add note about opening feature request for ARM support
  • refactor: Remove Jellystat service type
  • MediaCurator now has built-in watch statistics tracking
  • Jellystat integration no longer needed
  • Removed from frontend ServiceType, service options
  • Removed from backend models and schemas
  • feat: Add individual service sync jobs in Jobs tab
  • Add separate sync jobs for each enabled service
  • Show service sync status with running indicator
  • Add manual 'Sync Now' button per service
  • Display last sync result and duration
  • Auto-refresh job status every 5 seconds
  • New API endpoint POST /jobs/sync/service/{id}
  • Service sync jobs show in job history
  • fix: Emby sync creates MediaItems and populates watch statistics
  • Sync libraries, movies, series, episodes directly from Emby
  • Path-based library association for proper linking
  • Track user total_plays and total_watch_time_seconds
  • Use external_id for watch data matching
  • Include RunTimeTicks for watch time calculation
  • refactor(sync): Emby now matches existing items by PATH instead of creating duplicates

BREAKING CHANGE: Emby sync architecture completely redesigned

The core insight:

  • Sonarr/Radarr CREATE MediaItems with file paths and metadata
  • Emby PROVIDES watch statistics (plays, progress, favorites)
  • Previous code created DUPLICATE items from Emby with different external_ids

New behavior:

  • _sync_emby() no longer creates MediaItems
  • Loads ALL existing items and builds path -> item mapping
  • Matches Emby items to Sonarr/Radarr items by normalized PATH
  • Updates library_id based on Emby library paths
  • Applies watch data (play count, is_watched, favorites, progress) to matched items
  • Updates user statistics and watch history

Key changes:

  • Removed: external_id_to_item mapping (was causing duplicates)
  • Added: path_to_item mapping with normalized paths (/ instead of )
  • track_watch_data() now uses paths, skips items not in database
  • _sync_active_sessions() simplified to use only path_to_item
  • currently_watching_ids -> currently_watching_paths
  • Return value updated (Emby reports 0 added, only updated counts)

This fixes:

  • Movies showing 0 plays (Emby data was on separate items)
  • Libraries showing 0 counts
  • Users showing no watch data
  • Activity/history not tracking properly
  • feat: WebSocket real-time job system + Setup Wizard

WebSocket System:

  • Add ConnectionManager (backend/app/core/websocket.py)
  • Add /api/ws/jobs endpoint with ping/pong support
  • Add progress callbacks to Sonarr, Radarr, Emby sync
  • Integrate WebSocket broadcasts in all scheduler jobs
  • Add Zustand job store (frontend/src/stores/jobs.ts)
  • Add global WebSocket hook with auto-reconnect & toasts
  • Rewrite Jobs page with live progress bars & running panel
  • Add animated job count badge in Layout sidebar

Setup Wizard:

  • Add backend API: /api/setup/status, test-connection, add-service, complete, skip
  • Add 5-step frontend wizard (Welcome → Arr → MediaServer → Sync → Complete)
  • Add SetupGate redirect in App.tsx for first-time setup
  • Enforce service order: Sonarr/Radarr before Emby/Jellyfin

Docs:

  • Update DEVELOPMENT_STATUS.md with new features
  • fix: resolve all priority 1-5 bugs from DEVELOPMENT_STATUS.md

BUG-001 (CRITICAL): LibraryDetail.tsx complete rewrite

  • Fix double /api/ prefix causing 404 errors on all API calls
  • Migrate from manual useState/useEffect to React Query (useQuery)
  • Remove local formatBytes, formatDuration, formatDate, formatRelativeTime
  • Import shared utilities from lib/utils.ts
  • Add proper light/dark mode classes throughout

BUG-002 (HIGH): Fix Login.tsx & Register.tsx light-mode

  • Replace hardcoded dark classes with light/dark pairs
  • Fix: bg-dark-800 → bg-white dark:bg-dark-800
  • Fix: text-white → text-gray-900 dark:text-white
  • Fix: text-dark-200 → text-gray-700 dark:text-dark-200
  • Fix: border-dark-700 → border-gray-200 dark:border-dark-700
  • Fix inputs: bg-gray-50 dark:bg-dark-800, proper placeholder colors

BUG-003 (HIGH): Fix ConfirmDialog.tsx light-mode

  • Modal background, title, message, footer, cancel button themed

BUG-004 (HIGH): Fix Skeleton.tsx light-mode

  • Base skeleton: bg-gray-200 dark:bg-dark-700
  • Card/Stats containers: bg-white dark:bg-dark-800

BUG-005 (MEDIUM): Fix Toast theming in main.tsx

  • Replace hardcoded hex colors with Tailwind CSS classes
  • Toasts now respect light/dark mode automatically

BUG-006 (MEDIUM): Fix German locale in utils.ts

  • Change formatDate and formatDateTime from 'de-DE' to 'en-US'
  • Add formatDuration utility function for shared use

BUG-008 (MEDIUM): Call fetchUser on app init

  • ProtectedRoute now calls fetchUser() on mount when token exists
  • Ensures fresh user data instead of potentially stale persisted state

BUG-009 (LOW): Remove duplicate formatBytes from Preview.tsx

  • Import from shared lib/utils.ts instead

BUG-010 (LOW): Fix manual debounce in Users.tsx

  • Replace setTimeout-based debounce with useDebounce hook
  • docs: update DEVELOPMENT_STATUS.md with Session 3 bugfix results

  • feat: UX improvements, recharts charts, code-splitting

  • Layout.tsx: German strings → English (BUG-006 complete)
  • ResponsiveTable: Add light mode classes (missing dark: variants)
  • Activity.tsx: useDebounce hook, shared utils (formatDurationLong,
    formatWatchTime), ResponsiveTable migration, 3× recharts charts
    (Daily Plays area, Day-of-Week bar, Hour-of-Day bar)
  • UserDetail.tsx: shared utils, ResponsiveTable migration
  • Staging.tsx: ResponsiveTable migration
  • Jobs.tsx: Executions table → ResponsiveTable
  • App.tsx: React.lazy code-splitting for 13 pages with Suspense
  • utils.ts: Add formatDurationLong and formatWatchTime shared functions
  • DEVELOPMENT_STATUS.md: Update for Session 4
  • feat: Phase 2 enhancements - ResponsiveTable, filters, dashboard charts
  • LibraryDetail.tsx: Migrate Media + Activity tabs to ResponsiveTable
  • Activity.tsx: Add Library-Filter dropdown + Items-per-Page selector (10/25/50/100)
  • UserDetail.tsx: Add Library-Filter on activity tab
  • Dashboard.tsx: Add 3x recharts charts (Daily Plays, Day-of-Week, Hour-of-Day)
  • PLANNED_FEATURES.md: Update Phase 2/3 status, add Implementation History
  • DEVELOPMENT_STATUS.md: Update for Session 5
  • fix: int32 overflow on position_ticks/runtime_ticks + expand-rows + accessibility

BUG-011: PlaybackActivity position_ticks/runtime_ticks Integer→BigInteger

  • Emby tick values exceed int32 max (~2.1B), e.g. 70223183889
  • Added PostgreSQL migration (ALTER COLUMN TYPE BIGINT)
  • Added db.rollback() in _sync_active_sessions and services.py error handlers

ResponsiveTable: Expand-Row support

  • New props: onRowClick, isExpanded, expandedContent
  • Desktop: expanded content as extra with colSpan
  • Mobile: expanded content as div below card

Preview.tsx: Migrated both tables (Series + Movies) to ResponsiveTable

  • Series table with expandable season breakdown
  • Last page to complete ResponsiveTable migration

Expand-Rows on Activity, UserDetail, LibraryDetail

  • IP Address, Device, Play Method (color-coded), Progress bar
  • Library Activity API: added ip_address, transcode_video, transcode_audio

ConfirmDialog accessibility

  • role=dialog, aria-modal, aria-labelledby, focus trap, Escape key, click-outside

Documentation: DEVELOPMENT_STATUS.md + PLANNED_FEATURES.md updated

  • docs: fix inconsistencies in DEVELOPMENT_STATUS.md
  • Update commit hash from Pending to ea6e64c
  • Mark Preview.tsx migration as complete in Priority 2
  • Clean up strikethroughs in Priority 4 (Activity, Dashboard fully done)
  • Update ResponsiveTable comment (now used on all pages)...
Read more

Release 4.0.0

13 Apr 07:10
e8c047d

Choose a tag to compare

What's Changed in 4.0.0

Other Changes

  • Develop (#55)
  • feat: Complete Phase 2 - Users, Activity & Library Detail Views
  • Add PlaybackActivity model for detailed playback session tracking
  • Add activity API routes (/api/activity/) with list, stats, active sessions
  • Add users API routes (/api/users/) with list, detail, activity endpoints
  • Extend Emby sync with _sync_active_sessions() for real-time session tracking
  • Add Users.tsx page with search, pagination, user stats
  • Add UserDetail.tsx page with Overview/Activity tabs and time-based stats
  • Add Activity.tsx page with global activity log, active sessions, stats cards
  • Add LibraryDetail.tsx with Overview/Media/Activity tabs
  • Extend libraries API with /details, /media, /activity endpoints
  • Update navigation with Users and Activity menu items
  • Library cards now link to detail view

Completes Phase 2 of PLANNED_FEATURES.md roadmap (Jellystat-style features)

  • feat: Add PostgreSQL support and fix sync issues

Database:

  • Add PostgreSQL support via POSTGRES_* environment variables
  • Add asyncpg driver to requirements
  • Create docker-compose.postgres.yml for PostgreSQL setup
  • Keep SQLite as default for simple deployments
  • Add connection pooling for PostgreSQL

Bug Fixes:

  • Fix MediaItem.parent_id AttributeError by using series_id (external_id)
  • Add parent_id column to MediaItem model for future use
  • Fix Users API to fallback to UserWatchHistory when PlaybackActivity is empty
  • Fix deprecation warning: regex -> pattern in Query parameters
  • Remove 'Jellystat-style' comments from codebase

Improvements:

  • Sync jobs now visible in Jobs view with execution logs
  • Manual sync shows progress/errors in Jobs history
  • Users page shows last watched from UserWatchHistory fallback
  • chore: Update PostgreSQL to version 18 (latest stable)

  • fix: Add PostgreSQL support to database migrations

  • Add column_exists() helper for SQLite/PostgreSQL compatibility
  • Add table_exists() helper for SQLite/PostgreSQL compatibility
  • Use information_schema for PostgreSQL column/table checks
  • Use pragma_table_info for SQLite column checks
  • Add IF NOT EXISTS for PostgreSQL ALTER TABLE commands
  • Use SERIAL PRIMARY KEY for PostgreSQL auto-increment
  • chore: Remove ARM64 build to speed up CI
  • Build only linux/amd64 for faster builds
  • Remove QEMU setup (not needed without cross-platform builds)
  • Update release notes to reflect single architecture
  • Add note about opening feature request for ARM support
  • refactor: Remove Jellystat service type
  • MediaCurator now has built-in watch statistics tracking
  • Jellystat integration no longer needed
  • Removed from frontend ServiceType, service options
  • Removed from backend models and schemas
  • feat: Add individual service sync jobs in Jobs tab
  • Add separate sync jobs for each enabled service
  • Show service sync status with running indicator
  • Add manual 'Sync Now' button per service
  • Display last sync result and duration
  • Auto-refresh job status every 5 seconds
  • New API endpoint POST /jobs/sync/service/{id}
  • Service sync jobs show in job history
  • fix: Emby sync creates MediaItems and populates watch statistics
  • Sync libraries, movies, series, episodes directly from Emby
  • Path-based library association for proper linking
  • Track user total_plays and total_watch_time_seconds
  • Use external_id for watch data matching
  • Include RunTimeTicks for watch time calculation
  • refactor(sync): Emby now matches existing items by PATH instead of creating duplicates

BREAKING CHANGE: Emby sync architecture completely redesigned

The core insight:

  • Sonarr/Radarr CREATE MediaItems with file paths and metadata
  • Emby PROVIDES watch statistics (plays, progress, favorites)
  • Previous code created DUPLICATE items from Emby with different external_ids

New behavior:

  • _sync_emby() no longer creates MediaItems
  • Loads ALL existing items and builds path -> item mapping
  • Matches Emby items to Sonarr/Radarr items by normalized PATH
  • Updates library_id based on Emby library paths
  • Applies watch data (play count, is_watched, favorites, progress) to matched items
  • Updates user statistics and watch history

Key changes:

  • Removed: external_id_to_item mapping (was causing duplicates)
  • Added: path_to_item mapping with normalized paths (/ instead of )
  • track_watch_data() now uses paths, skips items not in database
  • _sync_active_sessions() simplified to use only path_to_item
  • currently_watching_ids -> currently_watching_paths
  • Return value updated (Emby reports 0 added, only updated counts)

This fixes:

  • Movies showing 0 plays (Emby data was on separate items)
  • Libraries showing 0 counts
  • Users showing no watch data
  • Activity/history not tracking properly
  • feat: WebSocket real-time job system + Setup Wizard

WebSocket System:

  • Add ConnectionManager (backend/app/core/websocket.py)
  • Add /api/ws/jobs endpoint with ping/pong support
  • Add progress callbacks to Sonarr, Radarr, Emby sync
  • Integrate WebSocket broadcasts in all scheduler jobs
  • Add Zustand job store (frontend/src/stores/jobs.ts)
  • Add global WebSocket hook with auto-reconnect & toasts
  • Rewrite Jobs page with live progress bars & running panel
  • Add animated job count badge in Layout sidebar

Setup Wizard:

  • Add backend API: /api/setup/status, test-connection, add-service, complete, skip
  • Add 5-step frontend wizard (Welcome → Arr → MediaServer → Sync → Complete)
  • Add SetupGate redirect in App.tsx for first-time setup
  • Enforce service order: Sonarr/Radarr before Emby/Jellyfin

Docs:

  • Update DEVELOPMENT_STATUS.md with new features
  • fix: resolve all priority 1-5 bugs from DEVELOPMENT_STATUS.md

BUG-001 (CRITICAL): LibraryDetail.tsx complete rewrite

  • Fix double /api/ prefix causing 404 errors on all API calls
  • Migrate from manual useState/useEffect to React Query (useQuery)
  • Remove local formatBytes, formatDuration, formatDate, formatRelativeTime
  • Import shared utilities from lib/utils.ts
  • Add proper light/dark mode classes throughout

BUG-002 (HIGH): Fix Login.tsx & Register.tsx light-mode

  • Replace hardcoded dark classes with light/dark pairs
  • Fix: bg-dark-800 → bg-white dark:bg-dark-800
  • Fix: text-white → text-gray-900 dark:text-white
  • Fix: text-dark-200 → text-gray-700 dark:text-dark-200
  • Fix: border-dark-700 → border-gray-200 dark:border-dark-700
  • Fix inputs: bg-gray-50 dark:bg-dark-800, proper placeholder colors

BUG-003 (HIGH): Fix ConfirmDialog.tsx light-mode

  • Modal background, title, message, footer, cancel button themed

BUG-004 (HIGH): Fix Skeleton.tsx light-mode

  • Base skeleton: bg-gray-200 dark:bg-dark-700
  • Card/Stats containers: bg-white dark:bg-dark-800

BUG-005 (MEDIUM): Fix Toast theming in main.tsx

  • Replace hardcoded hex colors with Tailwind CSS classes
  • Toasts now respect light/dark mode automatically

BUG-006 (MEDIUM): Fix German locale in utils.ts

  • Change formatDate and formatDateTime from 'de-DE' to 'en-US'
  • Add formatDuration utility function for shared use

BUG-008 (MEDIUM): Call fetchUser on app init

  • ProtectedRoute now calls fetchUser() on mount when token exists
  • Ensures fresh user data instead of potentially stale persisted state

BUG-009 (LOW): Remove duplicate formatBytes from Preview.tsx

  • Import from shared lib/utils.ts instead

BUG-010 (LOW): Fix manual debounce in Users.tsx

  • Replace setTimeout-based debounce with useDebounce hook
  • docs: update DEVELOPMENT_STATUS.md with Session 3 bugfix results

  • feat: UX improvements, recharts charts, code-splitting

  • Layout.tsx: German strings → English (BUG-006 complete)
  • ResponsiveTable: Add light mode classes (missing dark: variants)
  • Activity.tsx: useDebounce hook, shared utils (formatDurationLong,
    formatWatchTime), ResponsiveTable migration, 3× recharts charts
    (Daily Plays area, Day-of-Week bar, Hour-of-Day bar)
  • UserDetail.tsx: shared utils, ResponsiveTable migration
  • Staging.tsx: ResponsiveTable migration
  • Jobs.tsx: Executions table → ResponsiveTable
  • App.tsx: React.lazy code-splitting for 13 pages with Suspense
  • utils.ts: Add formatDurationLong and formatWatchTime shared functions
  • DEVELOPMENT_STATUS.md: Update for Session 4
  • feat: Phase 2 enhancements - ResponsiveTable, filters, dashboard charts
  • LibraryDetail.tsx: Migrate Media + Activity tabs to ResponsiveTable
  • Activity.tsx: Add Library-Filter dropdown + Items-per-Page selector (10/25/50/100)
  • UserDetail.tsx: Add Library-Filter on activity tab
  • Dashboard.tsx: Add 3x recharts charts (Daily Plays, Day-of-Week, Hour-of-Day)
  • PLANNED_FEATURES.md: Update Phase 2/3 status, add Implementation History
  • DEVELOPMENT_STATUS.md: Update for Session 5
  • fix: int32 overflow on position_ticks/runtime_ticks + expand-rows + accessibility

BUG-011: PlaybackActivity position_ticks/runtime_ticks Integer→BigInteger

  • Emby tick values exceed int32 max (~2.1B), e.g. 70223183889
  • Added PostgreSQL migration (ALTER COLUMN TYPE BIGINT)
  • Added db.rollback() in _sync_active_sessions and services.py error handlers

ResponsiveTable: Expand-Row support

  • New props: onRowClick, isExpanded, expandedContent
  • Desktop: expanded content as extra with colSpan
  • Mobile: expanded content as div below card

Preview.tsx: Migrated both tables (Series + Movies) to ResponsiveTable

  • Series table with expandable season breakdown
  • Last page to complete ResponsiveTable migration

Expand-Rows on Activity, UserDetail, LibraryDetail

  • IP Address, Device, Play Method (color-coded), Progress bar
  • Library Activity API: added ip_address, transcode_video, transcode_audio

ConfirmDialog accessibility

  • role=dialog, aria-modal, aria-labelledby, focus trap, Escape key, click-outside

Documentation: DEVELOPMENT_STATUS.md + PLANNED_FEATURES.md updated

  • docs: fix inconsistencies in DEVELOPMENT_STATUS.md
  • Update commit hash from Pending to ea6e64c
  • Mark Preview.tsx migration as complete in Priority 2
  • Clean up strikethroughs in Priority 4 (Activity, Dashboard fully done)
  • Update ResponsiveTable comment (now used on all pages)
  • C...
Read more

Development Build 3.0.0-dev

13 Apr 06:37
315658d

Choose a tag to compare

Pre-release

What's Changed in 3.0.0-dev

Other Changes

  • Merge branch 'main' into develop

Other Changes

  • Develop (#47)
  • feat: Complete Phase 2 - Users, Activity & Library Detail Views
  • Add PlaybackActivity model for detailed playback session tracking
  • Add activity API routes (/api/activity/) with list, stats, active sessions
  • Add users API routes (/api/users/) with list, detail, activity endpoints
  • Extend Emby sync with _sync_active_sessions() for real-time session tracking
  • Add Users.tsx page with search, pagination, user stats
  • Add UserDetail.tsx page with Overview/Activity tabs and time-based stats
  • Add Activity.tsx page with global activity log, active sessions, stats cards
  • Add LibraryDetail.tsx with Overview/Media/Activity tabs
  • Extend libraries API with /details, /media, /activity endpoints
  • Update navigation with Users and Activity menu items
  • Library cards now link to detail view

Completes Phase 2 of PLANNED_FEATURES.md roadmap (Jellystat-style features)

  • feat: Add PostgreSQL support and fix sync issues

Database:

  • Add PostgreSQL support via POSTGRES_* environment variables
  • Add asyncpg driver to requirements
  • Create docker-compose.postgres.yml for PostgreSQL setup
  • Keep SQLite as default for simple deployments
  • Add connection pooling for PostgreSQL

Bug Fixes:

  • Fix MediaItem.parent_id AttributeError by using series_id (external_id)
  • Add parent_id column to MediaItem model for future use
  • Fix Users API to fallback to UserWatchHistory when PlaybackActivity is empty
  • Fix deprecation warning: regex -> pattern in Query parameters
  • Remove 'Jellystat-style' comments from codebase

Improvements:

  • Sync jobs now visible in Jobs view with execution logs
  • Manual sync shows progress/errors in Jobs history
  • Users page shows last watched from UserWatchHistory fallback
  • chore: Update PostgreSQL to version 18 (latest stable)

  • fix: Add PostgreSQL support to database migrations

  • Add column_exists() helper for SQLite/PostgreSQL compatibility
  • Add table_exists() helper for SQLite/PostgreSQL compatibility
  • Use information_schema for PostgreSQL column/table checks
  • Use pragma_table_info for SQLite column checks
  • Add IF NOT EXISTS for PostgreSQL ALTER TABLE commands
  • Use SERIAL PRIMARY KEY for PostgreSQL auto-increment
  • chore: Remove ARM64 build to speed up CI
  • Build only linux/amd64 for faster builds
  • Remove QEMU setup (not needed without cross-platform builds)
  • Update release notes to reflect single architecture
  • Add note about opening feature request for ARM support
  • refactor: Remove Jellystat service type
  • MediaCurator now has built-in watch statistics tracking
  • Jellystat integration no longer needed
  • Removed from frontend ServiceType, service options
  • Removed from backend models and schemas
  • feat: Add individual service sync jobs in Jobs tab
  • Add separate sync jobs for each enabled service
  • Show service sync status with running indicator
  • Add manual 'Sync Now' button per service
  • Display last sync result and duration
  • Auto-refresh job status every 5 seconds
  • New API endpoint POST /jobs/sync/service/{id}
  • Service sync jobs show in job history
  • fix: Emby sync creates MediaItems and populates watch statistics
  • Sync libraries, movies, series, episodes directly from Emby
  • Path-based library association for proper linking
  • Track user total_plays and total_watch_time_seconds
  • Use external_id for watch data matching
  • Include RunTimeTicks for watch time calculation
  • refactor(sync): Emby now matches existing items by PATH instead of creating duplicates

BREAKING CHANGE: Emby sync architecture completely redesigned

The core insight:

  • Sonarr/Radarr CREATE MediaItems with file paths and metadata
  • Emby PROVIDES watch statistics (plays, progress, favorites)
  • Previous code created DUPLICATE items from Emby with different external_ids

New behavior:

  • _sync_emby() no longer creates MediaItems
  • Loads ALL existing items and builds path -> item mapping
  • Matches Emby items to Sonarr/Radarr items by normalized PATH
  • Updates library_id based on Emby library paths
  • Applies watch data (play count, is_watched, favorites, progress) to matched items
  • Updates user statistics and watch history

Key changes:

  • Removed: external_id_to_item mapping (was causing duplicates)
  • Added: path_to_item mapping with normalized paths (/ instead of )
  • track_watch_data() now uses paths, skips items not in database
  • _sync_active_sessions() simplified to use only path_to_item
  • currently_watching_ids -> currently_watching_paths
  • Return value updated (Emby reports 0 added, only updated counts)

This fixes:

  • Movies showing 0 plays (Emby data was on separate items)
  • Libraries showing 0 counts
  • Users showing no watch data
  • Activity/history not tracking properly
  • feat: WebSocket real-time job system + Setup Wizard

WebSocket System:

  • Add ConnectionManager (backend/app/core/websocket.py)
  • Add /api/ws/jobs endpoint with ping/pong support
  • Add progress callbacks to Sonarr, Radarr, Emby sync
  • Integrate WebSocket broadcasts in all scheduler jobs
  • Add Zustand job store (frontend/src/stores/jobs.ts)
  • Add global WebSocket hook with auto-reconnect & toasts
  • Rewrite Jobs page with live progress bars & running panel
  • Add animated job count badge in Layout sidebar

Setup Wizard:

  • Add backend API: /api/setup/status, test-connection, add-service, complete, skip
  • Add 5-step frontend wizard (Welcome → Arr → MediaServer → Sync → Complete)
  • Add SetupGate redirect in App.tsx for first-time setup
  • Enforce service order: Sonarr/Radarr before Emby/Jellyfin

Docs:

  • Update DEVELOPMENT_STATUS.md with new features
  • fix: resolve all priority 1-5 bugs from DEVELOPMENT_STATUS.md

BUG-001 (CRITICAL): LibraryDetail.tsx complete rewrite

  • Fix double /api/ prefix causing 404 errors on all API calls
  • Migrate from manual useState/useEffect to React Query (useQuery)
  • Remove local formatBytes, formatDuration, formatDate, formatRelativeTime
  • Import shared utilities from lib/utils.ts
  • Add proper light/dark mode classes throughout

BUG-002 (HIGH): Fix Login.tsx & Register.tsx light-mode

  • Replace hardcoded dark classes with light/dark pairs
  • Fix: bg-dark-800 → bg-white dark:bg-dark-800
  • Fix: text-white → text-gray-900 dark:text-white
  • Fix: text-dark-200 → text-gray-700 dark:text-dark-200
  • Fix: border-dark-700 → border-gray-200 dark:border-dark-700
  • Fix inputs: bg-gray-50 dark:bg-dark-800, proper placeholder colors

BUG-003 (HIGH): Fix ConfirmDialog.tsx light-mode

  • Modal background, title, message, footer, cancel button themed

BUG-004 (HIGH): Fix Skeleton.tsx light-mode

  • Base skeleton: bg-gray-200 dark:bg-dark-700
  • Card/Stats containers: bg-white dark:bg-dark-800

BUG-005 (MEDIUM): Fix Toast theming in main.tsx

  • Replace hardcoded hex colors with Tailwind CSS classes
  • Toasts now respect light/dark mode automatically

BUG-006 (MEDIUM): Fix German locale in utils.ts

  • Change formatDate and formatDateTime from 'de-DE' to 'en-US'
  • Add formatDuration utility function for shared use

BUG-008 (MEDIUM): Call fetchUser on app init

  • ProtectedRoute now calls fetchUser() on mount when token exists
  • Ensures fresh user data instead of potentially stale persisted state

BUG-009 (LOW): Remove duplicate formatBytes from Preview.tsx

  • Import from shared lib/utils.ts instead

BUG-010 (LOW): Fix manual debounce in Users.tsx

  • Replace setTimeout-based debounce with useDebounce hook
  • docs: update DEVELOPMENT_STATUS.md with Session 3 bugfix results

  • feat: UX improvements, recharts charts, code-splitting

  • Layout.tsx: German strings → English (BUG-006 complete)
  • ResponsiveTable: Add light mode classes (missing dark: variants)
  • Activity.tsx: useDebounce hook, shared utils (formatDurationLong,
    formatWatchTime), ResponsiveTable migration, 3× recharts charts
    (Daily Plays area, Day-of-Week bar, Hour-of-Day bar)
  • UserDetail.tsx: shared utils, ResponsiveTable migration
  • Staging.tsx: ResponsiveTable migration
  • Jobs.tsx: Executions table → ResponsiveTable
  • App.tsx: React.lazy code-splitting for 13 pages with Suspense
  • utils.ts: Add formatDurationLong and formatWatchTime shared functions
  • DEVELOPMENT_STATUS.md: Update for Session 4
  • feat: Phase 2 enhancements - ResponsiveTable, filters, dashboard charts
  • LibraryDetail.tsx: Migrate Media + Activity tabs to ResponsiveTable
  • Activity.tsx: Add Library-Filter dropdown + Items-per-Page selector (10/25/50/100)
  • UserDetail.tsx: Add Library-Filter on activity tab
  • Dashboard.tsx: Add 3x recharts charts (Daily Plays, Day-of-Week, Hour-of-Day)
  • PLANNED_FEATURES.md: Update Phase 2/3 status, add Implementation History
  • DEVELOPMENT_STATUS.md: Update for Session 5
  • fix: int32 overflow on position_ticks/runtime_ticks + expand-rows + accessibility

BUG-011: PlaybackActivity position_ticks/runtime_ticks Integer→BigInteger

  • Emby tick values exceed int32 max (~2.1B), e.g. 70223183889
  • Added PostgreSQL migration (ALTER COLUMN TYPE BIGINT)
  • Added db.rollback() in _sync_active_sessions and services.py error handlers

ResponsiveTable: Expand-Row support

  • New props: onRowClick, isExpanded, expandedContent
  • Desktop: expanded content as extra with colSpan
  • Mobile: expanded content as div below card

Preview.tsx: Migrated both tables (Series + Movies) to ResponsiveTable

  • Series table with expandable season breakdown
  • Last page to complete ResponsiveTable migration

Expand-Rows on Activity, UserDetail, LibraryDetail

  • IP Address, Device, Play Method (color-coded), Progress bar
  • Library Activity API: added ip_address, transcode_video, transcode_audio

ConfirmDialog accessibility

  • role=dialog, aria-modal, aria-labelledby, focus trap, Escape key, click-outside

Documentation: DEVELOPMENT_STATUS.md + PLANNED_FEATURES.md updated

  • docs: fix inconsistencies in DEVELOPMENT_STATUS.md
  • Update commit hash from Pending to ea6e64c
  • Mark Preview.tsx migration as complete in Priority 2
  • Clean up strikethroughs in Priority 4 (Activity, Dashboard fully done)
  • ...
Read more

Development Build 2.0.1-dev

13 Apr 06:35
f4c2fc8

Choose a tag to compare

Pre-release

What's Changed in 2.0.1-dev


Docker Images

This release is available as a Docker image for amd64 architecture:

Pull the image:

# Specific version
docker pull ghcr.io/Serph91P/mediacurator:2.0.1-dev

# Or latest stable (main branch)
docker pull ghcr.io/Serph91P/mediacurator:latest

# Or development (develop branch)
docker pull ghcr.io/Serph91P/mediacurator:dev

Run with Docker Compose:

# Download docker-compose.yml
curl -O https://raw.githubusercontent.com/Serph91P/MediaCurator/main/docker-compose.yml

# Start services
docker compose up -d

Registry Information

Property Value
Registry GitHub Container Registry (ghcr.io)
Image ghcr.io/Serph91P/mediacurator
Version 2.0.1-dev
Architecture linux/amd64

Note: ARM64 builds are not currently provided. Open a feature request if you need ARM support.

Documentation

See the README.md for full configuration options.

Development Build 2.0.0-dev

13 Apr 06:33
b228cb5

Choose a tag to compare

Pre-release

What's Changed in 2.0.0-dev


Docker Images

This release is available as a Docker image for amd64 architecture:

Pull the image:

# Specific version
docker pull ghcr.io/Serph91P/mediacurator:2.0.0-dev

# Or latest stable (main branch)
docker pull ghcr.io/Serph91P/mediacurator:latest

# Or development (develop branch)
docker pull ghcr.io/Serph91P/mediacurator:dev

Run with Docker Compose:

# Download docker-compose.yml
curl -O https://raw.githubusercontent.com/Serph91P/MediaCurator/main/docker-compose.yml

# Start services
docker compose up -d

Registry Information

Property Value
Registry GitHub Container Registry (ghcr.io)
Image ghcr.io/Serph91P/mediacurator
Version 2.0.0-dev
Architecture linux/amd64

Note: ARM64 builds are not currently provided. Open a feature request if you need ARM support.

Documentation

See the README.md for full configuration options.

Release 1.0.0

15 Mar 15:02
60ac5d0

Choose a tag to compare

What's Changed in 1.0.0

Other Changes

  • Develop (#47)
  • feat: Complete Phase 2 - Users, Activity & Library Detail Views
  • Add PlaybackActivity model for detailed playback session tracking
  • Add activity API routes (/api/activity/) with list, stats, active sessions
  • Add users API routes (/api/users/) with list, detail, activity endpoints
  • Extend Emby sync with _sync_active_sessions() for real-time session tracking
  • Add Users.tsx page with search, pagination, user stats
  • Add UserDetail.tsx page with Overview/Activity tabs and time-based stats
  • Add Activity.tsx page with global activity log, active sessions, stats cards
  • Add LibraryDetail.tsx with Overview/Media/Activity tabs
  • Extend libraries API with /details, /media, /activity endpoints
  • Update navigation with Users and Activity menu items
  • Library cards now link to detail view

Completes Phase 2 of PLANNED_FEATURES.md roadmap (Jellystat-style features)

  • feat: Add PostgreSQL support and fix sync issues

Database:

  • Add PostgreSQL support via POSTGRES_* environment variables
  • Add asyncpg driver to requirements
  • Create docker-compose.postgres.yml for PostgreSQL setup
  • Keep SQLite as default for simple deployments
  • Add connection pooling for PostgreSQL

Bug Fixes:

  • Fix MediaItem.parent_id AttributeError by using series_id (external_id)
  • Add parent_id column to MediaItem model for future use
  • Fix Users API to fallback to UserWatchHistory when PlaybackActivity is empty
  • Fix deprecation warning: regex -> pattern in Query parameters
  • Remove 'Jellystat-style' comments from codebase

Improvements:

  • Sync jobs now visible in Jobs view with execution logs
  • Manual sync shows progress/errors in Jobs history
  • Users page shows last watched from UserWatchHistory fallback
  • chore: Update PostgreSQL to version 18 (latest stable)

  • fix: Add PostgreSQL support to database migrations

  • Add column_exists() helper for SQLite/PostgreSQL compatibility
  • Add table_exists() helper for SQLite/PostgreSQL compatibility
  • Use information_schema for PostgreSQL column/table checks
  • Use pragma_table_info for SQLite column checks
  • Add IF NOT EXISTS for PostgreSQL ALTER TABLE commands
  • Use SERIAL PRIMARY KEY for PostgreSQL auto-increment
  • chore: Remove ARM64 build to speed up CI
  • Build only linux/amd64 for faster builds
  • Remove QEMU setup (not needed without cross-platform builds)
  • Update release notes to reflect single architecture
  • Add note about opening feature request for ARM support
  • refactor: Remove Jellystat service type
  • MediaCurator now has built-in watch statistics tracking
  • Jellystat integration no longer needed
  • Removed from frontend ServiceType, service options
  • Removed from backend models and schemas
  • feat: Add individual service sync jobs in Jobs tab
  • Add separate sync jobs for each enabled service
  • Show service sync status with running indicator
  • Add manual 'Sync Now' button per service
  • Display last sync result and duration
  • Auto-refresh job status every 5 seconds
  • New API endpoint POST /jobs/sync/service/{id}
  • Service sync jobs show in job history
  • fix: Emby sync creates MediaItems and populates watch statistics
  • Sync libraries, movies, series, episodes directly from Emby
  • Path-based library association for proper linking
  • Track user total_plays and total_watch_time_seconds
  • Use external_id for watch data matching
  • Include RunTimeTicks for watch time calculation
  • refactor(sync): Emby now matches existing items by PATH instead of creating duplicates

BREAKING CHANGE: Emby sync architecture completely redesigned

The core insight:

  • Sonarr/Radarr CREATE MediaItems with file paths and metadata
  • Emby PROVIDES watch statistics (plays, progress, favorites)
  • Previous code created DUPLICATE items from Emby with different external_ids

New behavior:

  • _sync_emby() no longer creates MediaItems
  • Loads ALL existing items and builds path -> item mapping
  • Matches Emby items to Sonarr/Radarr items by normalized PATH
  • Updates library_id based on Emby library paths
  • Applies watch data (play count, is_watched, favorites, progress) to matched items
  • Updates user statistics and watch history

Key changes:

  • Removed: external_id_to_item mapping (was causing duplicates)
  • Added: path_to_item mapping with normalized paths (/ instead of )
  • track_watch_data() now uses paths, skips items not in database
  • _sync_active_sessions() simplified to use only path_to_item
  • currently_watching_ids -> currently_watching_paths
  • Return value updated (Emby reports 0 added, only updated counts)

This fixes:

  • Movies showing 0 plays (Emby data was on separate items)
  • Libraries showing 0 counts
  • Users showing no watch data
  • Activity/history not tracking properly
  • feat: WebSocket real-time job system + Setup Wizard

WebSocket System:

  • Add ConnectionManager (backend/app/core/websocket.py)
  • Add /api/ws/jobs endpoint with ping/pong support
  • Add progress callbacks to Sonarr, Radarr, Emby sync
  • Integrate WebSocket broadcasts in all scheduler jobs
  • Add Zustand job store (frontend/src/stores/jobs.ts)
  • Add global WebSocket hook with auto-reconnect & toasts
  • Rewrite Jobs page with live progress bars & running panel
  • Add animated job count badge in Layout sidebar

Setup Wizard:

  • Add backend API: /api/setup/status, test-connection, add-service, complete, skip
  • Add 5-step frontend wizard (Welcome → Arr → MediaServer → Sync → Complete)
  • Add SetupGate redirect in App.tsx for first-time setup
  • Enforce service order: Sonarr/Radarr before Emby/Jellyfin

Docs:

  • Update DEVELOPMENT_STATUS.md with new features
  • fix: resolve all priority 1-5 bugs from DEVELOPMENT_STATUS.md

BUG-001 (CRITICAL): LibraryDetail.tsx complete rewrite

  • Fix double /api/ prefix causing 404 errors on all API calls
  • Migrate from manual useState/useEffect to React Query (useQuery)
  • Remove local formatBytes, formatDuration, formatDate, formatRelativeTime
  • Import shared utilities from lib/utils.ts
  • Add proper light/dark mode classes throughout

BUG-002 (HIGH): Fix Login.tsx & Register.tsx light-mode

  • Replace hardcoded dark classes with light/dark pairs
  • Fix: bg-dark-800 → bg-white dark:bg-dark-800
  • Fix: text-white → text-gray-900 dark:text-white
  • Fix: text-dark-200 → text-gray-700 dark:text-dark-200
  • Fix: border-dark-700 → border-gray-200 dark:border-dark-700
  • Fix inputs: bg-gray-50 dark:bg-dark-800, proper placeholder colors

BUG-003 (HIGH): Fix ConfirmDialog.tsx light-mode

  • Modal background, title, message, footer, cancel button themed

BUG-004 (HIGH): Fix Skeleton.tsx light-mode

  • Base skeleton: bg-gray-200 dark:bg-dark-700
  • Card/Stats containers: bg-white dark:bg-dark-800

BUG-005 (MEDIUM): Fix Toast theming in main.tsx

  • Replace hardcoded hex colors with Tailwind CSS classes
  • Toasts now respect light/dark mode automatically

BUG-006 (MEDIUM): Fix German locale in utils.ts

  • Change formatDate and formatDateTime from 'de-DE' to 'en-US'
  • Add formatDuration utility function for shared use

BUG-008 (MEDIUM): Call fetchUser on app init

  • ProtectedRoute now calls fetchUser() on mount when token exists
  • Ensures fresh user data instead of potentially stale persisted state

BUG-009 (LOW): Remove duplicate formatBytes from Preview.tsx

  • Import from shared lib/utils.ts instead

BUG-010 (LOW): Fix manual debounce in Users.tsx

  • Replace setTimeout-based debounce with useDebounce hook
  • docs: update DEVELOPMENT_STATUS.md with Session 3 bugfix results

  • feat: UX improvements, recharts charts, code-splitting

  • Layout.tsx: German strings → English (BUG-006 complete)
  • ResponsiveTable: Add light mode classes (missing dark: variants)
  • Activity.tsx: useDebounce hook, shared utils (formatDurationLong,
    formatWatchTime), ResponsiveTable migration, 3× recharts charts
    (Daily Plays area, Day-of-Week bar, Hour-of-Day bar)
  • UserDetail.tsx: shared utils, ResponsiveTable migration
  • Staging.tsx: ResponsiveTable migration
  • Jobs.tsx: Executions table → ResponsiveTable
  • App.tsx: React.lazy code-splitting for 13 pages with Suspense
  • utils.ts: Add formatDurationLong and formatWatchTime shared functions
  • DEVELOPMENT_STATUS.md: Update for Session 4
  • feat: Phase 2 enhancements - ResponsiveTable, filters, dashboard charts
  • LibraryDetail.tsx: Migrate Media + Activity tabs to ResponsiveTable
  • Activity.tsx: Add Library-Filter dropdown + Items-per-Page selector (10/25/50/100)
  • UserDetail.tsx: Add Library-Filter on activity tab
  • Dashboard.tsx: Add 3x recharts charts (Daily Plays, Day-of-Week, Hour-of-Day)
  • PLANNED_FEATURES.md: Update Phase 2/3 status, add Implementation History
  • DEVELOPMENT_STATUS.md: Update for Session 5
  • fix: int32 overflow on position_ticks/runtime_ticks + expand-rows + accessibility

BUG-011: PlaybackActivity position_ticks/runtime_ticks Integer→BigInteger

  • Emby tick values exceed int32 max (~2.1B), e.g. 70223183889
  • Added PostgreSQL migration (ALTER COLUMN TYPE BIGINT)
  • Added db.rollback() in _sync_active_sessions and services.py error handlers

ResponsiveTable: Expand-Row support

  • New props: onRowClick, isExpanded, expandedContent
  • Desktop: expanded content as extra with colSpan
  • Mobile: expanded content as div below card

Preview.tsx: Migrated both tables (Series + Movies) to ResponsiveTable

  • Series table with expandable season breakdown
  • Last page to complete ResponsiveTable migration

Expand-Rows on Activity, UserDetail, LibraryDetail

  • IP Address, Device, Play Method (color-coded), Progress bar
  • Library Activity API: added ip_address, transcode_video, transcode_audio

ConfirmDialog accessibility

  • role=dialog, aria-modal, aria-labelledby, focus trap, Escape key, click-outside

Documentation: DEVELOPMENT_STATUS.md + PLANNED_FEATURES.md updated

  • docs: fix inconsistencies in DEVELOPMENT_STATUS.md
  • Update commit hash from Pending to ea6e64c
  • Mark Preview.tsx migration as complete in Priority 2
  • Clean up strikethroughs in Priority 4 (Activity, Dashboard fully done)
  • Update ResponsiveTable comment (now used on all pages)
  • C...
Read more

Development Build 0.0.282-dev

15 Mar 14:51
37ffca0

Choose a tag to compare

Pre-release

What's Changed in 0.0.282-dev

CI/CD

  • Unify versioning with conventional commits auto-bump (#46)

Docker Images

This release is available as a Docker image for amd64 architecture:

Pull the image:

# Specific version
docker pull ghcr.io/Serph91P/mediacurator:0.0.282-dev

# Or latest stable (main branch)
docker pull ghcr.io/Serph91P/mediacurator:latest

# Or development (develop branch)
docker pull ghcr.io/Serph91P/mediacurator:dev

Run with Docker Compose:

# Download docker-compose.yml
curl -O https://raw.githubusercontent.com/Serph91P/MediaCurator/main/docker-compose.yml

# Start services
docker compose up -d

Registry Information

Property Value
Registry GitHub Container Registry (ghcr.io)
Image ghcr.io/Serph91P/mediacurator
Version 0.0.282-dev
Architecture linux/amd64

Note: ARM64 builds are not currently provided. Open a feature request if you need ARM support.

Documentation

See the README.md for full configuration options.

Release 0.0.136

13 Mar 15:25
122b49c

Choose a tag to compare

What's Changed in 0.0.136

Other Changes

  • Develop (#45)
  • feat: Complete Phase 2 - Users, Activity & Library Detail Views
  • Add PlaybackActivity model for detailed playback session tracking
  • Add activity API routes (/api/activity/) with list, stats, active sessions
  • Add users API routes (/api/users/) with list, detail, activity endpoints
  • Extend Emby sync with _sync_active_sessions() for real-time session tracking
  • Add Users.tsx page with search, pagination, user stats
  • Add UserDetail.tsx page with Overview/Activity tabs and time-based stats
  • Add Activity.tsx page with global activity log, active sessions, stats cards
  • Add LibraryDetail.tsx with Overview/Media/Activity tabs
  • Extend libraries API with /details, /media, /activity endpoints
  • Update navigation with Users and Activity menu items
  • Library cards now link to detail view

Completes Phase 2 of PLANNED_FEATURES.md roadmap (Jellystat-style features)

  • feat: Add PostgreSQL support and fix sync issues

Database:

  • Add PostgreSQL support via POSTGRES_* environment variables
  • Add asyncpg driver to requirements
  • Create docker-compose.postgres.yml for PostgreSQL setup
  • Keep SQLite as default for simple deployments
  • Add connection pooling for PostgreSQL

Bug Fixes:

  • Fix MediaItem.parent_id AttributeError by using series_id (external_id)
  • Add parent_id column to MediaItem model for future use
  • Fix Users API to fallback to UserWatchHistory when PlaybackActivity is empty
  • Fix deprecation warning: regex -> pattern in Query parameters
  • Remove 'Jellystat-style' comments from codebase

Improvements:

  • Sync jobs now visible in Jobs view with execution logs
  • Manual sync shows progress/errors in Jobs history
  • Users page shows last watched from UserWatchHistory fallback
  • chore: Update PostgreSQL to version 18 (latest stable)

  • fix: Add PostgreSQL support to database migrations

  • Add column_exists() helper for SQLite/PostgreSQL compatibility
  • Add table_exists() helper for SQLite/PostgreSQL compatibility
  • Use information_schema for PostgreSQL column/table checks
  • Use pragma_table_info for SQLite column checks
  • Add IF NOT EXISTS for PostgreSQL ALTER TABLE commands
  • Use SERIAL PRIMARY KEY for PostgreSQL auto-increment
  • chore: Remove ARM64 build to speed up CI
  • Build only linux/amd64 for faster builds
  • Remove QEMU setup (not needed without cross-platform builds)
  • Update release notes to reflect single architecture
  • Add note about opening feature request for ARM support
  • refactor: Remove Jellystat service type
  • MediaCurator now has built-in watch statistics tracking
  • Jellystat integration no longer needed
  • Removed from frontend ServiceType, service options
  • Removed from backend models and schemas
  • feat: Add individual service sync jobs in Jobs tab
  • Add separate sync jobs for each enabled service
  • Show service sync status with running indicator
  • Add manual 'Sync Now' button per service
  • Display last sync result and duration
  • Auto-refresh job status every 5 seconds
  • New API endpoint POST /jobs/sync/service/{id}
  • Service sync jobs show in job history
  • fix: Emby sync creates MediaItems and populates watch statistics
  • Sync libraries, movies, series, episodes directly from Emby
  • Path-based library association for proper linking
  • Track user total_plays and total_watch_time_seconds
  • Use external_id for watch data matching
  • Include RunTimeTicks for watch time calculation
  • refactor(sync): Emby now matches existing items by PATH instead of creating duplicates

BREAKING CHANGE: Emby sync architecture completely redesigned

The core insight:

  • Sonarr/Radarr CREATE MediaItems with file paths and metadata
  • Emby PROVIDES watch statistics (plays, progress, favorites)
  • Previous code created DUPLICATE items from Emby with different external_ids

New behavior:

  • _sync_emby() no longer creates MediaItems
  • Loads ALL existing items and builds path -> item mapping
  • Matches Emby items to Sonarr/Radarr items by normalized PATH
  • Updates library_id based on Emby library paths
  • Applies watch data (play count, is_watched, favorites, progress) to matched items
  • Updates user statistics and watch history

Key changes:

  • Removed: external_id_to_item mapping (was causing duplicates)
  • Added: path_to_item mapping with normalized paths (/ instead of )
  • track_watch_data() now uses paths, skips items not in database
  • _sync_active_sessions() simplified to use only path_to_item
  • currently_watching_ids -> currently_watching_paths
  • Return value updated (Emby reports 0 added, only updated counts)

This fixes:

  • Movies showing 0 plays (Emby data was on separate items)
  • Libraries showing 0 counts
  • Users showing no watch data
  • Activity/history not tracking properly
  • feat: WebSocket real-time job system + Setup Wizard

WebSocket System:

  • Add ConnectionManager (backend/app/core/websocket.py)
  • Add /api/ws/jobs endpoint with ping/pong support
  • Add progress callbacks to Sonarr, Radarr, Emby sync
  • Integrate WebSocket broadcasts in all scheduler jobs
  • Add Zustand job store (frontend/src/stores/jobs.ts)
  • Add global WebSocket hook with auto-reconnect & toasts
  • Rewrite Jobs page with live progress bars & running panel
  • Add animated job count badge in Layout sidebar

Setup Wizard:

  • Add backend API: /api/setup/status, test-connection, add-service, complete, skip
  • Add 5-step frontend wizard (Welcome → Arr → MediaServer → Sync → Complete)
  • Add SetupGate redirect in App.tsx for first-time setup
  • Enforce service order: Sonarr/Radarr before Emby/Jellyfin

Docs:

  • Update DEVELOPMENT_STATUS.md with new features
  • fix: resolve all priority 1-5 bugs from DEVELOPMENT_STATUS.md

BUG-001 (CRITICAL): LibraryDetail.tsx complete rewrite

  • Fix double /api/ prefix causing 404 errors on all API calls
  • Migrate from manual useState/useEffect to React Query (useQuery)
  • Remove local formatBytes, formatDuration, formatDate, formatRelativeTime
  • Import shared utilities from lib/utils.ts
  • Add proper light/dark mode classes throughout

BUG-002 (HIGH): Fix Login.tsx & Register.tsx light-mode

  • Replace hardcoded dark classes with light/dark pairs
  • Fix: bg-dark-800 → bg-white dark:bg-dark-800
  • Fix: text-white → text-gray-900 dark:text-white
  • Fix: text-dark-200 → text-gray-700 dark:text-dark-200
  • Fix: border-dark-700 → border-gray-200 dark:border-dark-700
  • Fix inputs: bg-gray-50 dark:bg-dark-800, proper placeholder colors

BUG-003 (HIGH): Fix ConfirmDialog.tsx light-mode

  • Modal background, title, message, footer, cancel button themed

BUG-004 (HIGH): Fix Skeleton.tsx light-mode

  • Base skeleton: bg-gray-200 dark:bg-dark-700
  • Card/Stats containers: bg-white dark:bg-dark-800

BUG-005 (MEDIUM): Fix Toast theming in main.tsx

  • Replace hardcoded hex colors with Tailwind CSS classes
  • Toasts now respect light/dark mode automatically

BUG-006 (MEDIUM): Fix German locale in utils.ts

  • Change formatDate and formatDateTime from 'de-DE' to 'en-US'
  • Add formatDuration utility function for shared use

BUG-008 (MEDIUM): Call fetchUser on app init

  • ProtectedRoute now calls fetchUser() on mount when token exists
  • Ensures fresh user data instead of potentially stale persisted state

BUG-009 (LOW): Remove duplicate formatBytes from Preview.tsx

  • Import from shared lib/utils.ts instead

BUG-010 (LOW): Fix manual debounce in Users.tsx

  • Replace setTimeout-based debounce with useDebounce hook
  • docs: update DEVELOPMENT_STATUS.md with Session 3 bugfix results

  • feat: UX improvements, recharts charts, code-splitting

  • Layout.tsx: German strings → English (BUG-006 complete)
  • ResponsiveTable: Add light mode classes (missing dark: variants)
  • Activity.tsx: useDebounce hook, shared utils (formatDurationLong,
    formatWatchTime), ResponsiveTable migration, 3× recharts charts
    (Daily Plays area, Day-of-Week bar, Hour-of-Day bar)
  • UserDetail.tsx: shared utils, ResponsiveTable migration
  • Staging.tsx: ResponsiveTable migration
  • Jobs.tsx: Executions table → ResponsiveTable
  • App.tsx: React.lazy code-splitting for 13 pages with Suspense
  • utils.ts: Add formatDurationLong and formatWatchTime shared functions
  • DEVELOPMENT_STATUS.md: Update for Session 4
  • feat: Phase 2 enhancements - ResponsiveTable, filters, dashboard charts
  • LibraryDetail.tsx: Migrate Media + Activity tabs to ResponsiveTable
  • Activity.tsx: Add Library-Filter dropdown + Items-per-Page selector (10/25/50/100)
  • UserDetail.tsx: Add Library-Filter on activity tab
  • Dashboard.tsx: Add 3x recharts charts (Daily Plays, Day-of-Week, Hour-of-Day)
  • PLANNED_FEATURES.md: Update Phase 2/3 status, add Implementation History
  • DEVELOPMENT_STATUS.md: Update for Session 5
  • fix: int32 overflow on position_ticks/runtime_ticks + expand-rows + accessibility

BUG-011: PlaybackActivity position_ticks/runtime_ticks Integer→BigInteger

  • Emby tick values exceed int32 max (~2.1B), e.g. 70223183889
  • Added PostgreSQL migration (ALTER COLUMN TYPE BIGINT)
  • Added db.rollback() in _sync_active_sessions and services.py error handlers

ResponsiveTable: Expand-Row support

  • New props: onRowClick, isExpanded, expandedContent
  • Desktop: expanded content as extra with colSpan
  • Mobile: expanded content as div below card

Preview.tsx: Migrated both tables (Series + Movies) to ResponsiveTable

  • Series table with expandable season breakdown
  • Last page to complete ResponsiveTable migration

Expand-Rows on Activity, UserDetail, LibraryDetail

  • IP Address, Device, Play Method (color-coded), Progress bar
  • Library Activity API: added ip_address, transcode_video, transcode_audio

ConfirmDialog accessibility

  • role=dialog, aria-modal, aria-labelledby, focus trap, Escape key, click-outside

Documentation: DEVELOPMENT_STATUS.md + PLANNED_FEATURES.md updated

  • docs: fix inconsistencies in DEVELOPMENT_STATUS.md
  • Update commit hash from Pending to ea6e64c
  • Mark Preview.tsx migration as complete in Priority 2
  • Clean up strikethroughs in Priority 4 (Activity, Dashboard fully done)
  • Update ResponsiveTable comment (now used on all pages)
    -...
Read more