// Playback reporting service // // Simplified service that delegates all logic to the Rust backend. // The backend handles: // - Local DB updates // - Jellyfin server reporting // - Offline queueing (via sync queue) // - Connectivity checks // // TRACES: UR-005, UR-019, UR-025 | DR-028, DR-047 import { invoke } from "@tauri-apps/api/core"; import { auth } from "$lib/stores/auth"; /** * Report playback start to Jellyfin (or queue if offline) * * The Rust backend handles both local DB updates and server reporting, * automatically queueing for sync if the server is unreachable. * * TRACES: UR-005, UR-025 | DR-028 */ export async function reportPlaybackStart( itemId: string, positionSeconds: number, contextType: "container" | "single" = "single", contextId: string | null = null ): Promise { const positionTicks = Math.floor(positionSeconds * 10000000); const userId = auth.getUserId(); console.log( "[PlaybackReporting] reportPlaybackStart - itemId:", itemId, "positionSeconds:", positionSeconds, "context:", contextType, contextId ); // Update local DB with context (always works, even offline) if (userId) { try { await invoke("storage_update_playback_context", { userId, itemId, positionTicks, contextType, contextId, }); } catch (e) { console.error("[PlaybackReporting] Failed to update playback context:", e); } } } /** * Report playback progress to Jellyfin (or queue if offline) * * Note: Progress reports are frequent and are not queued for sync. * The final position is captured by reportPlaybackStopped. * * TRACES: UR-005 | DR-028 */ export async function reportPlaybackProgress( itemId: string, positionSeconds: number, _isPaused = false ): Promise { const positionTicks = Math.floor(positionSeconds * 10000000); const userId = auth.getUserId(); // Reduce logging for frequent progress updates if (Math.floor(positionSeconds) % 30 === 0) { console.log("[PlaybackReporting] reportPlaybackProgress - itemId:", itemId, "position:", positionSeconds); } // Update local DB only (progress updates are frequent, don't report to server) if (userId) { try { await invoke("storage_update_playback_progress", { userId, itemId, positionTicks, }); } catch (e) { console.error("[PlaybackReporting] Failed to update local progress:", e); } } } /** * Report playback stopped to Jellyfin (or queue if offline) * * The Rust backend handles both local DB updates and server reporting, * automatically queuing for sync if the server is unreachable. * * TRACES: UR-005, UR-025 | DR-028 */ export async function reportPlaybackStopped(itemId: string, positionSeconds: number): Promise { const positionTicks = Math.floor(positionSeconds * 10000000); const userId = auth.getUserId(); console.log("[PlaybackReporting] reportPlaybackStopped - itemId:", itemId, "positionSeconds:", positionSeconds); // Update local DB first (always works, even offline) if (userId) { try { await invoke("storage_update_playback_progress", { userId, itemId, positionTicks, }); } catch (e) { console.error("[PlaybackReporting] Failed to update local progress:", e); } } // Queue for sync to server (the sync service will handle retry logic) if (userId && positionSeconds > 0) { try { // Get the repository to check if we should queue const repo = auth.getRepository(); await repo.reportPlaybackStopped(itemId, positionTicks); } catch (e) { console.error("[PlaybackReporting] Failed to report to server:", e); // Server error - could queue, but for now just log } } } /** * Mark an item as played (100% progress) * * TRACES: UR-025 | DR-028 */ export async function markAsPlayed(itemId: string): Promise { const userId = auth.getUserId(); console.log("[PlaybackReporting] markAsPlayed - itemId:", itemId); // Update local DB first if (userId) { try { await invoke("storage_mark_played", { userId, itemId }); } catch (e) { console.error("[PlaybackReporting] Failed to mark as played in local DB:", e); } } // Try to report to server via repository (handles queuing internally) try { const repo = auth.getRepository(); const item = await repo.getItem(itemId); if (item.runTimeTicks) { await repo.reportPlaybackStopped(itemId, item.runTimeTicks); } } catch (e) { console.error("[PlaybackReporting] Failed to report as played:", e); } }