fix(favorites): scope reorder position writes by playlist

The global favorites reorder wrote the new position filtering only by
content_id, so two Xtream playlists holding a favorite with the same
content_id would clobber each other's persisted order (greptile P1).

Thread playlist_id through the whole reorder path — the renderer builder
(UnifiedCollectionItem already carries playlistId), the IPC contract
(ElectronBridgeFavoriteReorderUpdate + inline payload types), the worker
op — and scope the prepared UPDATE by (contentId, playlistId), matching
the favorites composite unique index.

Tests: favorites.operations.spec asserts the playlistId placeholder and
per-row playlistId payload; preload contract fixture updated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
4grayandClaude Opus 4.8 committed 2026-07-07 08:26:19 +02:00
1 parent 5cc69d72b1
commit 4fa1872964
8 files changed
+36 -11

No files matched your search

@@ -807,12 +807,17 @@ export class UnifiedFavoritesDataService {
}
private buildXtreamPositionUpdates(items: UnifiedCollectionItem[]) {
const updates: { content_id: number; position: number }[] = [];
const updates: {
content_id: number;
playlist_id: string;
position: number;
}[] = [];
for (const item of items) {
if (item.sourceType === 'xtream' && item.contentId != null) {
updates.push({
content_id: item.contentId,
playlist_id: item.playlistId,
position: updates.length,
});
}
@@ -414,6 +414,8 @@ export interface ElectronBridgeGlobalRecentlyAddedItem extends ElectronBridgeXtr
export interface ElectronBridgeFavoriteReorderUpdate {
content_id: number;
/** Favorites are playlist-scoped — scope the position write per playlist */
playlist_id: string;
position: number;
}