-- Ratings CREATE TABLE IF NOT EXISTS ratings ( id TEXT PRIMARY KEY, user_id TEXT NOT NULL, media_id TEXT NOT NULL, stars INTEGER NOT NULL CHECK (stars >= 1 AND stars <= 5), review_text TEXT, created_at TEXT NOT NULL DEFAULT (datetime('now')), UNIQUE(user_id, media_id), FOREIGN KEY (media_id) REFERENCES media_items(id) ON DELETE CASCADE ); -- Comments CREATE TABLE IF NOT EXISTS comments ( id TEXT PRIMARY KEY, user_id TEXT NOT NULL, media_id TEXT NOT NULL, parent_comment_id TEXT, text TEXT NOT NULL, created_at TEXT NOT NULL DEFAULT (datetime('now')), FOREIGN KEY (media_id) REFERENCES media_items(id) ON DELETE CASCADE, FOREIGN KEY (parent_comment_id) REFERENCES comments(id) ON DELETE CASCADE ); -- Favorites CREATE TABLE IF NOT EXISTS favorites ( user_id TEXT NOT NULL, media_id TEXT NOT NULL, created_at TEXT NOT NULL DEFAULT (datetime('now')), PRIMARY KEY (user_id, media_id), FOREIGN KEY (media_id) REFERENCES media_items(id) ON DELETE CASCADE ); -- Share links CREATE TABLE IF NOT EXISTS share_links ( id TEXT PRIMARY KEY, media_id TEXT NOT NULL, created_by TEXT NOT NULL, token TEXT NOT NULL UNIQUE, password_hash TEXT, expires_at TEXT, view_count INTEGER NOT NULL DEFAULT 0, created_at TEXT NOT NULL DEFAULT (datetime('now')), FOREIGN KEY (media_id) REFERENCES media_items(id) ON DELETE CASCADE ); -- Playlists CREATE TABLE IF NOT EXISTS playlists ( id TEXT PRIMARY KEY, owner_id TEXT NOT NULL, name TEXT NOT NULL, description TEXT, is_public INTEGER NOT NULL DEFAULT 0, is_smart INTEGER NOT NULL DEFAULT 0, filter_query TEXT, created_at TEXT NOT NULL DEFAULT (datetime('now')), updated_at TEXT NOT NULL DEFAULT (datetime('now')) ); -- Playlist items CREATE TABLE IF NOT EXISTS playlist_items ( playlist_id TEXT NOT NULL, media_id TEXT NOT NULL, position INTEGER NOT NULL DEFAULT 0, added_at TEXT NOT NULL DEFAULT (datetime('now')), PRIMARY KEY (playlist_id, media_id), FOREIGN KEY (playlist_id) REFERENCES playlists(id) ON DELETE CASCADE, FOREIGN KEY (media_id) REFERENCES media_items(id) ON DELETE CASCADE ); -- Usage events CREATE TABLE IF NOT EXISTS usage_events ( id TEXT PRIMARY KEY, media_id TEXT, user_id TEXT, event_type TEXT NOT NULL, timestamp TEXT NOT NULL DEFAULT (datetime('now')), duration_secs REAL, context_json TEXT, FOREIGN KEY (media_id) REFERENCES media_items(id) ON DELETE SET NULL ); CREATE INDEX IF NOT EXISTS idx_usage_events_media ON usage_events(media_id); CREATE INDEX IF NOT EXISTS idx_usage_events_user ON usage_events(user_id); CREATE INDEX IF NOT EXISTS idx_usage_events_timestamp ON usage_events(timestamp); -- Watch history / progress CREATE TABLE IF NOT EXISTS watch_history ( id TEXT PRIMARY KEY, user_id TEXT NOT NULL, media_id TEXT NOT NULL, progress_secs REAL NOT NULL DEFAULT 0, last_watched TEXT NOT NULL DEFAULT (datetime('now')), UNIQUE(user_id, media_id), FOREIGN KEY (media_id) REFERENCES media_items(id) ON DELETE CASCADE ); -- Subtitles CREATE TABLE IF NOT EXISTS subtitles ( id TEXT PRIMARY KEY, media_id TEXT NOT NULL, language TEXT, format TEXT NOT NULL, file_path TEXT, is_embedded INTEGER NOT NULL DEFAULT 0, track_index INTEGER, offset_ms INTEGER NOT NULL DEFAULT 0, created_at TEXT NOT NULL DEFAULT (datetime('now')), FOREIGN KEY (media_id) REFERENCES media_items(id) ON DELETE CASCADE ); CREATE INDEX IF NOT EXISTS idx_subtitles_media ON subtitles(media_id); -- External metadata (enrichment) CREATE TABLE IF NOT EXISTS external_metadata ( id TEXT PRIMARY KEY, media_id TEXT NOT NULL, source TEXT NOT NULL, external_id TEXT, metadata_json TEXT NOT NULL DEFAULT '{}', confidence REAL NOT NULL DEFAULT 0.0, last_updated TEXT NOT NULL DEFAULT (datetime('now')), FOREIGN KEY (media_id) REFERENCES media_items(id) ON DELETE CASCADE ); CREATE INDEX IF NOT EXISTS idx_external_metadata_media ON external_metadata(media_id); -- Transcode sessions CREATE TABLE IF NOT EXISTS transcode_sessions ( id TEXT PRIMARY KEY, media_id TEXT NOT NULL, user_id TEXT, profile TEXT NOT NULL, cache_path TEXT NOT NULL, status TEXT NOT NULL DEFAULT 'pending', progress REAL NOT NULL DEFAULT 0.0, error_message TEXT, created_at TEXT NOT NULL DEFAULT (datetime('now')), expires_at TEXT, FOREIGN KEY (media_id) REFERENCES media_items(id) ON DELETE CASCADE ); CREATE INDEX IF NOT EXISTS idx_transcode_sessions_media ON transcode_sessions(media_id);