Major performance improvement: Replace manual history aggregation with
Tautulli's built-in stats APIs. This eliminates the need to fetch and
process thousands of history records on every page load.
Changes:
- useTautulliStats composable completely rewritten:
- Use get_home_stats for overall watch statistics (pre-aggregated)
- Use get_plays_by_date for daily activity (already grouped by day)
- Use get_plays_by_dayofweek for weekly patterns (pre-calculated)
- Use get_plays_by_hourofday for hourly distribution (pre-calculated)
- Remove fetchUserHistory() and manual aggregation functions
- ActivityPage updates:
- Fetch all data in parallel with Promise.all for faster loading
- Use user_id instead of username for better API performance
- Simplified data processing since API returns pre-aggregated data
Benefits:
- 10-100x faster data loading (no need to fetch/process full history)
- Reduced network bandwidth (smaller API responses)
- Less client-side computation (no manual aggregation)
- Better scalability for large time ranges (365+ days)
- Consistent with Tautulli's internal calculations
- TorrentTable: Condense to 2 columns on mobile (title+meta, actions)
- Title shown on first line, size/seeders on second line
- Hide separate seed/size columns on mobile (desktop only)
- Improved spacing and readability for mobile screens
- Standardize page layouts to match ActivityPage:
- TorrentsPage: Update header style, padding, and container structure
- GenPasswordPage: Align header and content layout with other pages
- Consistent 3rem desktop padding, 0.75rem mobile padding
- Unified h1 styling: 2rem desktop, 1.5rem mobile, font-weight 300
- Minor improvements:
- Remove console.log statements from usePlexApi
- Fix duration unit handling in useTautulliStats
- Adjust AdminStats label font sizing
- Reduce Graph.vue point radius for cleaner charts
Issue: ActivityPage and route guards showed "not authenticated"
even when Plex was linked via Settings page.
Root cause: Plex user data stored in localStorage but route guards
and ActivityPage only checked Vuex store (state.settings.plexUserId).
Changes:
- Update routes.ts hasPlexAccount() to check both:
1. Vuex store (user/plexUserId)
2. localStorage (plex_user_data) as fallback
- Update ActivityPage plexUserId computed to check both:
1. Vuex store first
2. localStorage plex_user_data.id as fallback
Why two sources?
- Vuex store: Set from JWT token (backend user settings)
- localStorage: Set immediately when linking Plex account
- localStorage persists across page reloads
- Provides seamless experience without backend round-trip
Now Activity page correctly shows data when Plex is linked ✓
Create useTautulliStats composable (247 lines):
- fetchUserHistory() - Get watch history from Tautulli API
- calculateWatchStats() - Total hours, plays by media type
- groupByDay() - Daily activity (plays & duration)
- groupByDayOfWeek() - Weekly patterns by media type
- getTopContent() - Most watched content ranking
- getHourlyDistribution() - Watch patterns by hour of day
Update ActivityPage.vue with new visualizations:
- Stats overview cards (4 metrics: plays, hours, movies, episodes)
- Activity per day line chart (plays or duration)
- Activity by media type stacked bar chart (movies/shows/music)
- NEW: Hourly distribution chart
- NEW: Top 10 most watched content list
Features:
- Direct Tautulli API integration (no backend needed)
- Real-time data from Plex watch history
- Configurable time range (days filter)
- Toggle between plays count and watch duration
- Responsive grid layout for stats cards
- Styled top content ranking with hover effects
Benefits:
- Rich visualization of actual watch patterns
- See viewing habits by time of day
- Identify most rewatched content
- Compare movie vs TV viewing
- All data from authoritative source (Tautulli)
ActivityPage now provides comprehensive watch analytics! 📊
Major improvements to Plex integration:
- Replace Vuex store dependency with localStorage-based connection detection
- Fetch and display real Plex user data (username, email, subscription, 2FA status)
- Add user badges: Plex Pass, member years, 2FA, experimental features
- Properly format Unix timestamp joined dates
- Remove success message box, add elegant checkmark icon next to username
- Add Plex connection badge to main user profile
Real-time Plex API integration:
- Fetch actual library counts from Plex server (movies, shows, music)
- Display real server name from user's Plex account
- Load recently added items with actual titles, years, and ratings
- Calculate real genre statistics from library metadata
- Compute actual duration totals from item metadata
- Count actual episodes (TV shows) and tracks (music)
- Sync library on demand with fresh data from Plex API
Interactive library modal:
- Replace toast messages with rich modal showing library details
- Display recently added items with poster images
- Show genre distribution with animated bar charts
- Add loading states with animated dots
- Disable empty library cards
- Modal appears above header with proper z-index
- Blur backdrop for better focus
- Fully responsive mobile design
Store Plex data in localStorage:
- Cache user profile data including subscription info
- Store auth token in secure cookie (30 day expiration)
- Load from cache for instant display on page load
- Refresh data on authentication and manual sync
Add Plex connection indicator to user profile:
- Orange Plex badge in settings profile header
- Shows 'Connected as [username]' below member info
- Loads username from localStorage on mount
- Remove unused imports and auto-refresh functionality
- Reduce padding and spacing for more compact admin layout
- Simplify stats generation and remove unused variables
- Adjust font sizes and icon sizes for better consistency
- Improve line-height on admin page title
- Minor performance optimizations
- Create single-page settings layout (removed sidebar navigation)
- Add large profile hero card with avatar, stats, and user info
- Display user stats: Requests and Magnets Added
- Compact spacing and improved typography hierarchy
- Section headers at 1.5rem for better hierarchy
- Reduced whitespace while maintaining readability
- Max-width: 800px for better content focus
* On every route change, update local variables from query params
* ResultSection is keyed to query to force re-render
* Resolved lint warnings
* replace webpack w/ vite
* update all imports with alias @ and scss
* vite environment variables, also typed
* upgraded eslint, defined new rules & added ignore comments
* resolved linting issues
* moved index.html to project root
* updated dockerfile w/ build stage before runtime image definition
* sign drone config