Files
jellytau/src/lib/services/favorites.ts
T
dtourolle ad48d89dfe chore(format): run prettier over src/ and scripts/
Formatting was configured but never enforced: `bun run format:check`
reported 199 unformatted files and ran in no workflow and in no git hook,
so .prettierrc (printWidth 100, trailing commas) described an intention
rather than the tree.

This is the one-time sweep that makes the check gateable. Whitespace and
token-reflow only -- no behavioural change: `bun run check` reports 0
errors and all 1053 frontend tests pass before and after.

Kept out of every other commit on purpose. A 199-file diff mixed with
real changes is unreviewable, and the next commit turns format:check
into a hard CI gate so this cannot silently accumulate again.
2026-08-21 17:41:44 +02:00

70 lines
2.4 KiB
TypeScript

// Favorites service - Handles toggling favorite status with optimistic updates
// TRACES: UR-017, UR-068 | DR-021, DR-119
import { get } from "svelte/store";
import { commands } from "$lib/api/bindings";
import { auth } from "$lib/stores/auth";
import { isConnected } from "$lib/stores/connectivity";
import { setFavorite } from "$lib/stores/favorites";
import { createLogger } from "$lib/utils/logger";
const log = createLogger("Favorites");
/**
* Toggle the favorite status of an item.
*
* Flow:
* 1. Update local database immediately (optimistic update)
* 2. Sync to Jellyfin server
* 3. Mark as synced on success, or leave pending_sync flag on failure
*
* @param itemId - The Jellyfin item ID
* @param currentIsFavorite - The current favorite status
* @returns The new favorite status
* @throws Error if not authenticated or database update fails
*/
export async function toggleFavorite(itemId: string, currentIsFavorite: boolean): Promise<boolean> {
const userId = auth.getUserId();
if (!userId) {
throw new Error("Not authenticated");
}
const newIsFavorite = !currentIsFavorite;
// 1. Update local database first (optimistic update)
await commands.storageToggleFavorite(userId, itemId, newIsFavorite);
// Publish to every mounted view at once, so the heart on a card, the detail
// page and the Favourites grid never disagree. TRACES: UR-068 | DR-119
setFavorite(itemId, newIsFavorite);
// 2. Sync to Jellyfin server.
//
// Only attempt this when we're actually connected. When offline, the server
// call can hang on a long network timeout rather than failing fast — which
// blocks the caller (and leaves the favorite button greyed out with a wait
// cursor) until the request finally gives up, effectively only recovering
// once we're back online. The local DB write above keeps the pending_sync
// flag set, so the change still syncs later; we just don't block the UI on
// an unreachable server here.
if (get(isConnected)) {
try {
const repo = auth.getRepository();
if (newIsFavorite) {
await repo.markFavorite(itemId);
} else {
await repo.unmarkFavorite(itemId);
}
// 3. Mark as synced
await commands.storageMarkSynced(userId, itemId);
} catch (error) {
log.error("Failed to sync favorite to server:", error);
// Favorite is stored locally and will be synced later
// via sync queue (when implemented)
}
}
return newIsFavorite;
}