mirror of
https://github.com/p-stream/p-stream.git
synced 2026-04-21 09:42:17 +00:00
disable collection/group syncing
This commit is contained in:
parent
6e5184501f
commit
387982d2f9
1 changed files with 140 additions and 138 deletions
|
|
@ -4,42 +4,42 @@ import { useInterval } from "react-use";
|
||||||
import { getPosterForMedia } from "@/backend/metadata/tmdb";
|
import { getPosterForMedia } from "@/backend/metadata/tmdb";
|
||||||
import { useBookmarkStore } from "@/stores/bookmarks";
|
import { useBookmarkStore } from "@/stores/bookmarks";
|
||||||
import { useTraktAuthStore } from "@/stores/trakt/store";
|
import { useTraktAuthStore } from "@/stores/trakt/store";
|
||||||
import { modifyBookmarks } from "@/utils/bookmarkModifications";
|
|
||||||
import { traktService } from "@/utils/trakt";
|
import { traktService } from "@/utils/trakt";
|
||||||
import { TraktContentData, TraktList } from "@/utils/traktTypes";
|
import { TraktContentData } from "@/utils/traktTypes";
|
||||||
|
|
||||||
const TRAKT_SYNC_INTERVAL_MS = 5 * 60 * 1000; // 5 min
|
const TRAKT_SYNC_INTERVAL_MS = 5 * 60 * 1000; // 5 min
|
||||||
const INITIAL_SYNC_DELAY_MS = 2000; // Re-sync after backend restore
|
const INITIAL_SYNC_DELAY_MS = 2000; // Re-sync after backend restore
|
||||||
|
|
||||||
function listId(list: TraktList): string {
|
// Collections/groups sync disabled for now - bookmarks only sync to watchlist
|
||||||
return list.ids.slug ?? String(list.ids.trakt);
|
// import { modifyBookmarks } from "@/utils/bookmarkModifications";
|
||||||
}
|
// import { TraktList } from "@/utils/traktTypes";
|
||||||
|
// function listId(list: TraktList): string {
|
||||||
async function findListByName(
|
// return list.ids.slug ?? String(list.ids.trakt);
|
||||||
username: string,
|
// }
|
||||||
groupName: string,
|
// async function findListByName(
|
||||||
): Promise<TraktList | null> {
|
// username: string,
|
||||||
const lists = await traktService.getLists(username);
|
// groupName: string,
|
||||||
return lists.find((l) => l.name === groupName) ?? null;
|
// ): Promise<TraktList | null> {
|
||||||
}
|
// const lists = await traktService.getLists(username);
|
||||||
|
// return lists.find((l) => l.name === groupName) ?? null;
|
||||||
async function ensureListExists(
|
// }
|
||||||
username: string,
|
// async function ensureListExists(
|
||||||
groupName: string,
|
// username: string,
|
||||||
): Promise<TraktList | null> {
|
// groupName: string,
|
||||||
const existing = await findListByName(username, groupName);
|
// ): Promise<TraktList | null> {
|
||||||
if (existing) return existing;
|
// const existing = await findListByName(username, groupName);
|
||||||
try {
|
// if (existing) return existing;
|
||||||
return await traktService.createList(username, groupName);
|
// try {
|
||||||
} catch {
|
// return await traktService.createList(username, groupName);
|
||||||
return null;
|
// } catch {
|
||||||
}
|
// return null;
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
export function TraktBookmarkSyncer() {
|
export function TraktBookmarkSyncer() {
|
||||||
const { traktUpdateQueue, removeTraktUpdateItem, replaceBookmarks } =
|
const { traktUpdateQueue, removeTraktUpdateItem, replaceBookmarks } =
|
||||||
useBookmarkStore();
|
useBookmarkStore();
|
||||||
const { accessToken, user } = useTraktAuthStore();
|
const { accessToken } = useTraktAuthStore();
|
||||||
const isSyncingRef = useRef(false);
|
const isSyncingRef = useRef(false);
|
||||||
const [hydrated, setHydrated] = useState(false);
|
const [hydrated, setHydrated] = useState(false);
|
||||||
|
|
||||||
|
|
@ -51,9 +51,6 @@ export function TraktBookmarkSyncer() {
|
||||||
const queue = [...traktUpdateQueue];
|
const queue = [...traktUpdateQueue];
|
||||||
if (queue.length === 0) return;
|
if (queue.length === 0) return;
|
||||||
|
|
||||||
const slug = user?.ids?.slug;
|
|
||||||
const hasLists = Boolean(slug);
|
|
||||||
|
|
||||||
for (const item of queue) {
|
for (const item of queue) {
|
||||||
removeTraktUpdateItem(item.id);
|
removeTraktUpdateItem(item.id);
|
||||||
|
|
||||||
|
|
@ -70,48 +67,50 @@ export function TraktBookmarkSyncer() {
|
||||||
|
|
||||||
if (item.action === "add") {
|
if (item.action === "add") {
|
||||||
await traktService.addToWatchlist(contentData);
|
await traktService.addToWatchlist(contentData);
|
||||||
if (hasLists) {
|
// Collections sync disabled - bookmarks only sync to watchlist
|
||||||
const newGroups = item.group ?? [];
|
// if (hasLists) {
|
||||||
const prevGroups = item.previousGroup ?? [];
|
// const newGroups = item.group ?? [];
|
||||||
|
// const prevGroups = item.previousGroup ?? [];
|
||||||
|
|
||||||
// Remove from Trakt lists that the bookmark no longer belongs to
|
// // Remove from Trakt lists that the bookmark no longer belongs to
|
||||||
const groupsToRemove = prevGroups.filter(
|
// const groupsToRemove = prevGroups.filter(
|
||||||
(g) => !newGroups.includes(g),
|
// (g) => !newGroups.includes(g),
|
||||||
);
|
// );
|
||||||
for (const groupName of groupsToRemove) {
|
// for (const groupName of groupsToRemove) {
|
||||||
const list = await findListByName(slug!, groupName);
|
// const list = await findListByName(slug!, groupName);
|
||||||
if (list) {
|
// if (list) {
|
||||||
await traktService.removeFromList(slug!, listId(list), [
|
// await traktService.removeFromList(slug!, listId(list), [
|
||||||
contentData,
|
// contentData,
|
||||||
]);
|
// ]);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Add to Trakt lists that are new
|
// // Add to Trakt lists that are new
|
||||||
const groupsToAdd = newGroups.filter(
|
// const groupsToAdd = newGroups.filter(
|
||||||
(g) => !prevGroups.includes(g),
|
// (g) => !prevGroups.includes(g),
|
||||||
);
|
// );
|
||||||
for (const groupName of groupsToAdd) {
|
// for (const groupName of groupsToAdd) {
|
||||||
const list = await ensureListExists(slug!, groupName);
|
// const list = await ensureListExists(slug!, groupName);
|
||||||
if (list) {
|
// if (list) {
|
||||||
await traktService.addToList(slug!, listId(list), [
|
// await traktService.addToList(slug!, listId(list), [
|
||||||
contentData,
|
// contentData,
|
||||||
]);
|
// ]);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
} else if (item.action === "delete") {
|
} else if (item.action === "delete") {
|
||||||
await traktService.removeFromWatchlist(contentData);
|
await traktService.removeFromWatchlist(contentData);
|
||||||
if (hasLists && item.group?.length) {
|
// Collections sync disabled - bookmarks only sync to watchlist
|
||||||
for (const groupName of item.group) {
|
// if (hasLists && item.group?.length) {
|
||||||
const list = await findListByName(slug!, groupName);
|
// for (const groupName of item.group) {
|
||||||
if (list) {
|
// const list = await findListByName(slug!, groupName);
|
||||||
await traktService.removeFromList(slug!, listId(list), [
|
// if (list) {
|
||||||
contentData,
|
// await traktService.removeFromList(slug!, listId(list), [
|
||||||
]);
|
// contentData,
|
||||||
}
|
// ]);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Failed to sync bookmark to Trakt", error);
|
console.error("Failed to sync bookmark to Trakt", error);
|
||||||
|
|
@ -120,19 +119,20 @@ export function TraktBookmarkSyncer() {
|
||||||
};
|
};
|
||||||
|
|
||||||
processQueue();
|
processQueue();
|
||||||
}, [accessToken, user?.ids?.slug, traktUpdateQueue, removeTraktUpdateItem]);
|
}, [accessToken, traktUpdateQueue, removeTraktUpdateItem]);
|
||||||
|
|
||||||
// Push local bookmarks to Trakt (watchlist + groups)
|
// Push local bookmarks to Trakt watchlist (TODO implement collections/groups sync)
|
||||||
const syncBookmarksToTrakt = useCallback(async () => {
|
const syncBookmarksToTrakt = useCallback(async () => {
|
||||||
if (!accessToken || isSyncingRef.current) return;
|
if (!accessToken || isSyncingRef.current) return;
|
||||||
const slug = useTraktAuthStore.getState().user?.ids?.slug;
|
// const slug = useTraktAuthStore.getState().user?.ids?.slug;
|
||||||
if (!slug) return;
|
// if (!slug) return;
|
||||||
isSyncingRef.current = true;
|
isSyncingRef.current = true;
|
||||||
try {
|
try {
|
||||||
if (!useTraktAuthStore.getState().user) {
|
if (!useTraktAuthStore.getState().user) {
|
||||||
await traktService.getUserProfile();
|
await traktService.getUserProfile();
|
||||||
}
|
}
|
||||||
const bookmarks = useBookmarkStore.getState().bookmarks;
|
const bookmarks = useBookmarkStore.getState().bookmarks;
|
||||||
|
|
||||||
for (const [tmdbId, b] of Object.entries(bookmarks)) {
|
for (const [tmdbId, b] of Object.entries(bookmarks)) {
|
||||||
try {
|
try {
|
||||||
const contentData: TraktContentData = {
|
const contentData: TraktContentData = {
|
||||||
|
|
@ -142,14 +142,15 @@ export function TraktBookmarkSyncer() {
|
||||||
type: b.type === "movie" ? "movie" : "show",
|
type: b.type === "movie" ? "movie" : "show",
|
||||||
};
|
};
|
||||||
await traktService.addToWatchlist(contentData);
|
await traktService.addToWatchlist(contentData);
|
||||||
if (b.group?.length) {
|
// Collections sync disabled - bookmarks only sync to watchlist
|
||||||
for (const groupName of b.group) {
|
// if (b.group?.length) {
|
||||||
const list = await ensureListExists(slug, groupName);
|
// for (const groupName of b.group) {
|
||||||
if (list) {
|
// const list = await ensureListExists(slug, groupName);
|
||||||
await traktService.addToList(slug, listId(list), [contentData]);
|
// if (list) {
|
||||||
}
|
// await traktService.addToList(slug, listId(list), [contentData]);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.warn("Failed to push bookmark to Trakt:", tmdbId, err);
|
console.warn("Failed to push bookmark to Trakt:", tmdbId, err);
|
||||||
}
|
}
|
||||||
|
|
@ -192,63 +193,64 @@ export function TraktBookmarkSyncer() {
|
||||||
|
|
||||||
replaceBookmarks(merged);
|
replaceBookmarks(merged);
|
||||||
|
|
||||||
const slug = useTraktAuthStore.getState().user?.ids?.slug;
|
// Collections sync disabled - only watchlist is synced, no Trakt lists
|
||||||
if (slug) {
|
// const slug = useTraktAuthStore.getState().user?.ids?.slug;
|
||||||
try {
|
// if (slug) {
|
||||||
const lists = await traktService.getLists(slug);
|
// try {
|
||||||
const currentBookmarks = useBookmarkStore.getState().bookmarks;
|
// const lists = await traktService.getLists(slug);
|
||||||
let modifiedBookmarks = { ...currentBookmarks };
|
// const currentBookmarks = useBookmarkStore.getState().bookmarks;
|
||||||
|
// let modifiedBookmarks = { ...currentBookmarks };
|
||||||
|
|
||||||
for (const list of lists) {
|
// for (const list of lists) {
|
||||||
const listTitle = list.name;
|
// const listTitle = list.name;
|
||||||
const items = await traktService.getListItems(slug, listId(list));
|
// const items = await traktService.getListItems(slug, listId(list));
|
||||||
for (const li of items) {
|
// for (const li of items) {
|
||||||
const media = li.movie || li.show;
|
// const media = li.movie || li.show;
|
||||||
if (!media?.ids?.tmdb) continue;
|
// if (!media?.ids?.tmdb) continue;
|
||||||
|
|
||||||
const tmdbId = media.ids.tmdb.toString();
|
// const tmdbId = media.ids.tmdb.toString();
|
||||||
const type = li.movie ? "movie" : "show";
|
// const type = li.movie ? "movie" : "show";
|
||||||
const bookmark = modifiedBookmarks[tmdbId];
|
// const bookmark = modifiedBookmarks[tmdbId];
|
||||||
|
|
||||||
if (!bookmark) {
|
// if (!bookmark) {
|
||||||
const poster = await getPosterForMedia(tmdbId, type);
|
// const poster = await getPosterForMedia(tmdbId, type);
|
||||||
modifiedBookmarks[tmdbId] = {
|
// modifiedBookmarks[tmdbId] = {
|
||||||
type: type as "movie" | "show",
|
// type: type as "movie" | "show",
|
||||||
title: media.title,
|
// title: media.title,
|
||||||
year: media.year,
|
// year: media.year,
|
||||||
poster,
|
// poster,
|
||||||
updatedAt: Date.now(),
|
// updatedAt: Date.now(),
|
||||||
group: [listTitle],
|
// group: [listTitle],
|
||||||
};
|
// };
|
||||||
} else {
|
// } else {
|
||||||
const groups = bookmark.group ?? [];
|
// const groups = bookmark.group ?? [];
|
||||||
if (!groups.includes(listTitle)) {
|
// if (!groups.includes(listTitle)) {
|
||||||
const { modifiedBookmarks: next } = modifyBookmarks(
|
// const { modifiedBookmarks: next } = modifyBookmarks(
|
||||||
modifiedBookmarks,
|
// modifiedBookmarks,
|
||||||
[tmdbId],
|
// [tmdbId],
|
||||||
{ addGroups: [listTitle] },
|
// { addGroups: [listTitle] },
|
||||||
);
|
// );
|
||||||
modifiedBookmarks = next;
|
// modifiedBookmarks = next;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
const hasNewBookmarks =
|
// const hasNewBookmarks =
|
||||||
Object.keys(modifiedBookmarks).length !==
|
// Object.keys(modifiedBookmarks).length !==
|
||||||
Object.keys(currentBookmarks).length;
|
// Object.keys(currentBookmarks).length;
|
||||||
const hasGroupChanges = Object.keys(modifiedBookmarks).some(
|
// const hasGroupChanges = Object.keys(modifiedBookmarks).some(
|
||||||
(id) =>
|
// (id) =>
|
||||||
JSON.stringify(modifiedBookmarks[id]?.group ?? []) !==
|
// JSON.stringify(modifiedBookmarks[id]?.group ?? []) !==
|
||||||
JSON.stringify(currentBookmarks[id]?.group ?? []),
|
// JSON.stringify(currentBookmarks[id]?.group ?? []),
|
||||||
);
|
// );
|
||||||
if (hasNewBookmarks || hasGroupChanges) {
|
// if (hasNewBookmarks || hasGroupChanges) {
|
||||||
replaceBookmarks(modifiedBookmarks);
|
// replaceBookmarks(modifiedBookmarks);
|
||||||
}
|
// }
|
||||||
} catch (listError) {
|
// } catch (listError) {
|
||||||
console.warn("Failed to sync Trakt lists (groups)", listError);
|
// console.warn("Failed to sync Trakt lists (groups)", listError);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Failed to sync Trakt watchlist to local", error);
|
console.error("Failed to sync Trakt watchlist to local", error);
|
||||||
} finally {
|
} finally {
|
||||||
|
|
@ -257,8 +259,9 @@ export function TraktBookmarkSyncer() {
|
||||||
}, [accessToken, replaceBookmarks]);
|
}, [accessToken, replaceBookmarks]);
|
||||||
|
|
||||||
const fullSync = useCallback(async () => {
|
const fullSync = useCallback(async () => {
|
||||||
await syncWatchlistFromTrakt(); // Pull Trakt → local, merge
|
// Push local → Trakt first so our changes reach Trakt before we pull
|
||||||
await syncBookmarksToTrakt(); // Push local → Trakt
|
await syncBookmarksToTrakt();
|
||||||
|
await syncWatchlistFromTrakt(); // Then pull Trakt → local, merge
|
||||||
}, [syncWatchlistFromTrakt, syncBookmarksToTrakt]);
|
}, [syncWatchlistFromTrakt, syncBookmarksToTrakt]);
|
||||||
|
|
||||||
// Wait for Trakt auth store to rehydrate from persist (accessToken may be null on first render)
|
// Wait for Trakt auth store to rehydrate from persist (accessToken may be null on first render)
|
||||||
|
|
@ -281,13 +284,12 @@ export function TraktBookmarkSyncer() {
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// On mount (after hydration): pull immediately (Trakt → local)
|
// On mount (after hydration): full sync (push then pull)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!hydrated || !accessToken) return;
|
if (!hydrated || !accessToken) return;
|
||||||
syncWatchlistFromTrakt();
|
|
||||||
const t = setTimeout(fullSync, INITIAL_SYNC_DELAY_MS);
|
const t = setTimeout(fullSync, INITIAL_SYNC_DELAY_MS);
|
||||||
return () => clearTimeout(t);
|
return () => clearTimeout(t);
|
||||||
}, [hydrated, accessToken, syncWatchlistFromTrakt, fullSync]);
|
}, [hydrated, accessToken, fullSync]);
|
||||||
|
|
||||||
// Periodic full sync (pull + push)
|
// Periodic full sync (pull + push)
|
||||||
useInterval(fullSync, TRAKT_SYNC_INTERVAL_MS);
|
useInterval(fullSync, TRAKT_SYNC_INTERVAL_MS);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue