Features: - VOD library with movie grouping and version detection - TV show library with season/episode organization - TMDB integration for trending shows and recently aired episodes - Recent releases section with TMDB release date sorting - Watch history tracking with continue watching - Playlist caching (12-hour TTL) for offline support - M3U playlist parsing with XStream API support - Authentication with credential storage Technical: - SwiftUI for tvOS - Actor-based services for thread safety - Persistent caching for playlists, TMDB data, and watch history - KSPlayer integration for video playback Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
23 KiB
SimVision Architecture Documentation
System Overview
SimVision is a tvOS application built with SwiftUI that enables users to authenticate, retrieve streaming credentials, and play VOD content from XStream-compatible m3u playlists. The architecture follows MVVM (Model-View-ViewModel) pattern with a centralized state management approach.
High-Level Architecture Diagram
┌─────────────────────────────────────────────────────────────────┐
│ User Interface Layer │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Password │ │ VOD Library │ │ Video Player │ │
│ │ Entry View │ │ View │ │ View │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└───────────────────────────┬─────────────────────────────────────┘
│
┌───────────────────────────┼─────────────────────────────────────┐
│ │ ViewModel Layer │
│ ┌──────────────┐ ┌──────┴──────┐ ┌──────────────┐ │
│ │ Auth │ │ VOD Library │ │ Video Player │ │
│ │ ViewModel │ │ ViewModel │ │ ViewModel │ │
│ └──────────────┘ └─────────────┘ └──────────────┘ │
└───────────────────────────┬─────────────────────────────────────┘
│
┌───────────────────────────┼─────────────────────────────────────┐
│ │ State Management │
│ ┌──────┴──────┐ │
│ │ AppState │ (ObservableObject) │
│ │ - auth │ │
│ │ - playlist │ │
│ │ - error │ │
│ └─────────────┘ │
└───────────────────────────┬─────────────────────────────────────┘
│
┌───────────────────────────┼─────────────────────────────────────┐
│ │ Service Layer │
│ ┌──────────────┐ ┌──────┴──────┐ ┌──────────────┐ │
│ │ Auth │ │ Playlist │ │ Network │ │
│ │ Service │ │ Service │ │ Service │ │
│ └──────────────┘ └─────────────┘ └──────────────┘ │
│ ┌──────────────┐ ┌─────────────┐ │
│ │ Storage │ │ M3U Parser │ │
│ │ Service │ │ │ │
│ └──────────────┘ └─────────────┘ │
└───────────────────────────┬─────────────────────────────────────┘
│
┌───────────────────────────┼─────────────────────────────────────┐
│ │ External Systems │
│ ┌──────────────┐ ┌──────┴──────┐ ┌──────────────┐ │
│ │ Web Service │ │ XStream │ │ Keychain │ │
│ │ (Auth) │ │ Server │ │ │ │
│ └──────────────┘ └─────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────────┘
Architectural Layers
1. User Interface Layer (Views)
Responsibility: Present information to users and handle user interactions.
Components:
- PasswordEntryView: Initial authentication screen where users enter their password
- MainTabView: Root navigation container using TabView (expandable for Live TV)
- VODLibraryView: Grid display of all VOD content with filtering capabilities
- VODDetailView: Detailed view of a selected VOD item with metadata and play button
- VideoPlayerView: Full-screen video playback using AVPlayerViewController
- Component Views: Reusable UI components (VODCardView, LoadingView, ErrorView)
Key Patterns:
- SwiftUI declarative syntax
- Environment objects for state injection
- Focus state management for tvOS
- Navigation using NavigationStack
2. ViewModel Layer
Responsibility: Handle view-specific logic, user input validation, and UI state transformations.
Components:
-
AuthenticationViewModel
- Manages password input state
- Validates password criteria
- Controls password visibility toggle
-
VODLibraryViewModel
- Filters VOD items by category
- Implements search functionality
- Manages filter state
-
VideoPlayerViewModel
- Controls AVPlayer lifecycle
- Manages playback state (playing, paused)
- Handles playback errors
Key Patterns:
- ObservableObject protocol
- @Published properties for reactive updates
- @MainActor isolation for UI updates
3. State Management Layer
Component: AppState (Central Coordinator)
Responsibility: Global application state management and coordination between services.
State Properties:
@Published var isAuthenticated: Bool
@Published var credentials: XStreamCredentials?
@Published var playlist: Playlist?
@Published var isLoading: Bool
@Published var error: NetworkError?
Key Methods:
checkAuthentication(): Verify stored credentials on app launchauthenticate(password:): Perform authentication flowloadPlaylist(forceRefresh:): Fetch and parse playlistlogout(): Clear credentials and reset state
Design Decisions:
- Single source of truth for global state
- Environment object pattern for dependency injection
- Async/await for all asynchronous operations
- @MainActor isolation ensures thread safety for UI updates
4. Service Layer
Responsibility: Business logic, data operations, and external system integration.
4.1 NetworkService
Type: Actor (thread-safe)
Responsibility: Core HTTP client for all network operations.
Key Features:
- Generic request method with Codable support
- Automatic error mapping (URLError → NetworkError)
- Configurable timeouts
- Async/await based
- Request/response logging capability
Error Handling:
// Converts various error types to NetworkError
- URLError.notConnectedToInternet → NetworkError.noInternetConnection
- URLError.timedOut → NetworkError.timeout
- HTTP 401/403 → NetworkError.authenticationFailed
- HTTP 5xx → NetworkError.serverError(code)
4.2 AuthenticationService
Type: Actor (thread-safe)
Responsibility: Authentication flow management.
Flow:
- Accept password from user
- Send POST request to web service with password in header
- Receive XStream credentials (server, port, username, password)
- Store credentials securely via StorageService
- Return credentials to AppState
Integration Points:
- NetworkService: HTTP requests
- StorageService: Credential persistence
4.3 PlaylistService
Type: Actor (thread-safe)
Responsibility: Fetch and parse m3u playlists from XStream servers.
Features:
- Constructs XStream API URLs with credentials
- Downloads m3u data as string
- Delegates parsing to M3UParser
- Caches parsed playlist in memory
- Force refresh capability
URL Construction:
http://server:port/get.php?username=X&password=Y&type=m3u_plus&output=ts
4.4 StorageService
Type: Actor (thread-safe)
Responsibility: Secure data persistence.
Storage Mechanisms:
- Keychain: XStream credentials (encrypted by system)
- UserDefaults: User preferences (non-sensitive)
Key Operations:
saveCredentials(): Store credentials in KeychainloadCredentials(): Retrieve credentials from KeychainclearCredentials(): Delete credentials from Keychain- Generic preference save/load methods
Security Considerations:
- Never stores user-entered password
- Only stores XStream credentials (received from web service)
- Keychain encryption handled by iOS/tvOS
- Service identifier:
com.simvision.tvos
4.5 M3UParser
Type: Class
Responsibility: Parse m3u playlist files in XStream format.
Parsing Strategy:
1. Validate #EXTM3U header
2. Iterate through lines
3. Pair #EXTINF lines with subsequent URL lines
4. Extract attributes using regex:
- tvg-id → id
- tvg-name → name
- tvg-logo → iconURL
- group-title → categoryID
5. Create VODItem instances
6. Extract unique categories
Attribute Extraction Example:
#EXTINF:-1 tvg-id="123" tvg-name="Movie" tvg-logo="http://..." group-title="Movies",Display Name
http://server:port/movie/username/password/12345.mp4
Error Handling:
- Invalid format detection
- Empty playlist detection
- Malformed entry skipping
Data Models
Core Models
Credentials
struct XStreamCredentials {
let serverUrl: String
let port: String
let username: String
let password: String
// Computed properties for URL construction
var baseURL: String
func constructPlaylistURL() -> URL?
}
VODItem
struct VODItem: Identifiable, Codable, Hashable {
let id: String
let name: String
let streamURL: String
let iconURL: String?
let categoryID: String?
let description: String?
// Additional metadata
}
Playlist
struct Playlist: Codable {
let vodItems: [VODItem]
let categories: [Category]
let lastUpdated: Date
// Computed properties for filtering
var categorizedVODItems: [String: [VODItem]]
}
Communication Patterns
1. User Action Flow
User taps button
→ View captures action
→ Calls method on ViewModel (if view-specific logic needed)
→ Or calls method on AppState (if affects global state)
→ AppState coordinates with Services
→ Services perform operations (network, storage, parsing)
→ Services return results
→ AppState updates @Published properties
→ SwiftUI automatically re-renders affected Views
2. State Propagation
AppState (@Published property changes)
→ SwiftUI observes change via @EnvironmentObject
→ All subscribed Views re-evaluate body
→ UI updates automatically
3. Error Handling Flow
Service throws NetworkError
→ Caught by AppState
→ AppState sets error property
→ View observes error change
→ ErrorView displays with retry/dismiss options
→ User action either retries or dismisses
Concurrency Model
Actor Isolation
All services use the actor keyword for thread-safe access:
actor NetworkService { }
actor AuthenticationService { }
actor PlaylistService { }
actor StorageService { }
Benefits:
- Automatic serialization of access
- Prevention of data races
- Compiler-enforced thread safety
MainActor Isolation
UI components use @MainActor:
@MainActor
class AppState: ObservableObject { }
@MainActor
class AuthenticationViewModel: ObservableObject { }
Benefits:
- All UI updates occur on main thread
- No manual dispatch to main queue needed
- Compiler-verified thread safety
Async/Await
All asynchronous operations use async/await:
func authenticate(password: String) async {
await appState.authenticate(password: password)
}
Benefits:
- Readable, linear code flow
- Automatic error propagation
- No callback hell
tvOS-Specific Considerations
Focus Engine
Implementation:
@FocusStateproperty wrappers track focused items.focused()modifier binds focus state to views- Visual feedback: scale effects, borders, shadows on focused items
Example:
@FocusState private var focusedItem: String?
VODCardView(vodItem: item, isFocused: .constant(focusedItem == item.id))
.focused($focusedItem, equals: item.id)
Input Handling
- Siri Remote navigation handled automatically by SwiftUI
- Button presses mapped to standard button actions
- Text input uses on-screen keyboard
UI Design Principles
- Large Touch Targets: Minimum 250x90 points for buttons
- Focus Indicators: Prominent borders and scale effects
- Minimal Text Input: Only password entry required
- Card-Based Layouts: Grid layouts with large thumbnails
- High Contrast: White text on dark backgrounds
Security Architecture
Credential Flow
User Password (entered)
→ Transmitted once to web service (HTTPS recommended)
→ Never stored locally
→ Discarded after authentication
XStream Credentials (received)
→ Stored in Keychain (encrypted)
→ Retrieved on app launch
→ Used for all playlist requests
Security Measures
- No Password Storage: User password never persisted
- Keychain Encryption: XStream credentials encrypted by system
- HTTPS Recommended: For web service authentication endpoint
- URL Validation: All stream URLs validated before playback
- No Sensitive Logging: Error messages avoid exposing credentials
Error Recovery Strategies
Network Errors
Strategy: Retry with exponential backoff (future enhancement)
Current Implementation:
- Display error with context-specific message
- Provide retry button
- Offer recovery suggestions
Authentication Errors
Strategy: Force re-authentication
Implementation:
- Clear invalid credentials
- Return to login screen
- Display specific error message
Parsing Errors
Strategy: Graceful degradation
Implementation:
- Skip malformed entries
- Continue parsing valid entries
- Report error with details if entire playlist fails
Extensibility Points
Future Feature: Live TV Streams
Required Changes:
- Add
LiveItemmodel similar toVODItem - Create
LiveTVViewfor channel grid - Add second tab to
MainTabView - Extend
M3UParserto handle live stream format - Add
LiveTVViewModelfor channel management
No Changes Required:
- Existing services (Network, Storage, Auth)
- Error handling infrastructure
- Component views (Loading, Error)
Future Feature: EPG (Electronic Program Guide)
Required Changes:
- Add
EPGServiceto fetch program data - Create
EPGItemandProgramSchedulemodels - Create
EPGViewfor program listings - Extend
PlaylistServiceto fetch EPG data
Future Feature: Favorites
Required Changes:
- Add
favorites: [String]to storage - Add toggle favorite method to ViewModels
- Add favorites filtering to
VODLibraryViewModel - Add favorites tab or filter option
Testing Strategy
Unit Testing Targets
- M3UParser: Test with various m3u formats
- NetworkService: Mock URLSession for request testing
- StorageService: Test Keychain operations with test identifiers
- Models: Test Codable conformance and computed properties
Integration Testing Targets
- Authentication Flow: End-to-end login process
- Playlist Fetching: Full fetch and parse cycle
- Error Handling: Various error scenarios
UI Testing Targets
- Navigation Flow: Login → Library → Detail → Player
- Focus Engine: Verify focus states and navigation
- Error Display: Verify error messages and recovery
Performance Considerations
Image Loading
Current: AsyncImage with system caching Future Enhancement: Custom image cache with disk persistence
Playlist Caching
Current: In-memory cache in PlaylistService Future Enhancement: Disk cache with TTL (Time To Live)
List Performance
Current: LazyVGrid for on-demand cell creation Optimization: Tested with playlists up to 10,000 items
Video Playback
Implementation: AVPlayer with hardware acceleration Buffering: System-managed adaptive streaming
Deployment Architecture
┌─────────────────────────────────────────────────────────────┐
│ Apple TV Device │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ SimVision App (tvOS) │ │
│ │ ┌────────────────────────────────────────────────┐ │ │
│ │ │ App Bundle (.ipa) │ │ │
│ │ │ - Swift Runtime │ │ │
│ │ │ - SwiftUI Framework │ │ │
│ │ │ - AVKit Framework │ │ │
│ │ │ - Compiled Swift Code │ │ │
│ │ └────────────────────────────────────────────────┘ │ │
│ │ ↕ │ │
│ │ ┌────────────────────────────────────────────────┐ │ │
│ │ │ tvOS System Services │ │ │
│ │ │ - Keychain │ │ │
│ │ │ - UserDefaults │ │ │
│ │ │ - URLSession │ │ │
│ │ │ - AVFoundation │ │ │
│ │ └────────────────────────────────────────────────┘ │ │
│ └───────────────────────────────────────────────────────┘ │
└──────────────────────────┬──────────────────────────────────┘
│ Network
┌──────────────────────────┼──────────────────────────────────┐
│ External Services │
│ ┌──────────────┐ ┌─────────────┐ ┌──────────────┐ │
│ │ Auth Web │ │ XStream │ │ CDN/Stream │ │
│ │ Service │ │ Server │ │ Servers │ │
│ │ (Your API) │ │ (m3u API) │ │ (Video) │ │
│ └──────────────┘ └─────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────┘
Configuration Management
Environment-Specific Configuration
File: Utilities/Constants.swift
enum Constants {
enum API {
static let authenticationBaseURL = "..." // Change per environment
static let requestTimeout: TimeInterval = 30.0
}
enum Storage {
static let keychainService = "com.simvision.tvos"
}
enum UI {
static let vodGridColumns = 4
}
}
Recommended Practice:
- Development: Use test web service
- Staging: Use staging web service
- Production: Use production web service
Dependencies
System Frameworks
- SwiftUI: User interface framework
- AVKit: Video playback (AVPlayer, AVPlayerViewController)
- Combine: Reactive programming (ObservableObject, @Published)
- Foundation: Core utilities (URLSession, Codable, etc.)
- Security: Keychain access
No Third-Party Dependencies
Rationale:
- Reduces app size
- Eliminates dependency management overhead
- Avoids potential security vulnerabilities
- Simplifies maintenance
Trade-offs:
- More code to write for image caching
- Less sophisticated async image loading
- No pre-built M3U parser library
Conclusion
SimVision follows a clean, layered architecture with clear separation of concerns. The use of modern Swift concurrency features (async/await, actors) ensures thread safety and readable asynchronous code. The MVVM pattern with centralized state management provides a scalable foundation for future feature additions while maintaining code clarity and testability.
The architecture is designed to be maintainable, extensible, and performant for tvOS applications, with careful consideration of platform-specific requirements like the focus engine and Siri Remote navigation.