mirror of
https://github.com/p-stream/p-stream.git
synced 2026-03-11 09:45:33 +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 { useBookmarkStore } from "@/stores/bookmarks";
|
||||
import { useTraktAuthStore } from "@/stores/trakt/store";
|
||||
import { modifyBookmarks } from "@/utils/bookmarkModifications";
|
||||
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 INITIAL_SYNC_DELAY_MS = 2000; // Re-sync after backend restore
|
||||
|
||||
function listId(list: TraktList): string {
|
||||
return list.ids.slug ?? String(list.ids.trakt);
|
||||
}
|
||||
|
||||
async function findListByName(
|
||||
username: string,
|
||||
groupName: string,
|
||||
): Promise<TraktList | null> {
|
||||
const lists = await traktService.getLists(username);
|
||||
return lists.find((l) => l.name === groupName) ?? null;
|
||||
}
|
||||
|
||||
async function ensureListExists(
|
||||
username: string,
|
||||
groupName: string,
|
||||
): Promise<TraktList | null> {
|
||||
const existing = await findListByName(username, groupName);
|
||||
if (existing) return existing;
|
||||
try {
|
||||
return await traktService.createList(username, groupName);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
// Collections/groups sync disabled for now - bookmarks only sync to watchlist
|
||||
// import { modifyBookmarks } from "@/utils/bookmarkModifications";
|
||||
// import { TraktList } from "@/utils/traktTypes";
|
||||
// function listId(list: TraktList): string {
|
||||
// return list.ids.slug ?? String(list.ids.trakt);
|
||||
// }
|
||||
// async function findListByName(
|
||||
// username: string,
|
||||
// groupName: string,
|
||||
// ): Promise<TraktList | null> {
|
||||
// const lists = await traktService.getLists(username);
|
||||
// return lists.find((l) => l.name === groupName) ?? null;
|
||||
// }
|
||||
// async function ensureListExists(
|
||||
// username: string,
|
||||
// groupName: string,
|
||||
// ): Promise<TraktList | null> {
|
||||
// const existing = await findListByName(username, groupName);
|
||||
// if (existing) return existing;
|
||||
// try {
|
||||
// return await traktService.createList(username, groupName);
|
||||
// } catch {
|
||||
// return null;
|
||||
// }
|
||||
// }
|
||||
|
||||
export function TraktBookmarkSyncer() {
|
||||
const { traktUpdateQueue, removeTraktUpdateItem, replaceBookmarks } =
|
||||
useBookmarkStore();
|
||||
const { accessToken, user } = useTraktAuthStore();
|
||||
const { accessToken } = useTraktAuthStore();
|
||||
const isSyncingRef = useRef(false);
|
||||
const [hydrated, setHydrated] = useState(false);
|
||||
|
||||
|
|
@ -51,9 +51,6 @@ export function TraktBookmarkSyncer() {
|
|||
const queue = [...traktUpdateQueue];
|
||||
if (queue.length === 0) return;
|
||||
|
||||
const slug = user?.ids?.slug;
|
||||
const hasLists = Boolean(slug);
|
||||
|
||||
for (const item of queue) {
|
||||
removeTraktUpdateItem(item.id);
|
||||
|
||||
|
|
@ -70,48 +67,50 @@ export function TraktBookmarkSyncer() {
|
|||
|
||||
if (item.action === "add") {
|
||||
await traktService.addToWatchlist(contentData);
|
||||
if (hasLists) {
|
||||
const newGroups = item.group ?? [];
|
||||
const prevGroups = item.previousGroup ?? [];
|
||||
// Collections sync disabled - bookmarks only sync to watchlist
|
||||
// if (hasLists) {
|
||||
// const newGroups = item.group ?? [];
|
||||
// const prevGroups = item.previousGroup ?? [];
|
||||
|
||||
// Remove from Trakt lists that the bookmark no longer belongs to
|
||||
const groupsToRemove = prevGroups.filter(
|
||||
(g) => !newGroups.includes(g),
|
||||
);
|
||||
for (const groupName of groupsToRemove) {
|
||||
const list = await findListByName(slug!, groupName);
|
||||
if (list) {
|
||||
await traktService.removeFromList(slug!, listId(list), [
|
||||
contentData,
|
||||
]);
|
||||
}
|
||||
}
|
||||
// // Remove from Trakt lists that the bookmark no longer belongs to
|
||||
// const groupsToRemove = prevGroups.filter(
|
||||
// (g) => !newGroups.includes(g),
|
||||
// );
|
||||
// for (const groupName of groupsToRemove) {
|
||||
// const list = await findListByName(slug!, groupName);
|
||||
// if (list) {
|
||||
// await traktService.removeFromList(slug!, listId(list), [
|
||||
// contentData,
|
||||
// ]);
|
||||
// }
|
||||
// }
|
||||
|
||||
// Add to Trakt lists that are new
|
||||
const groupsToAdd = newGroups.filter(
|
||||
(g) => !prevGroups.includes(g),
|
||||
);
|
||||
for (const groupName of groupsToAdd) {
|
||||
const list = await ensureListExists(slug!, groupName);
|
||||
if (list) {
|
||||
await traktService.addToList(slug!, listId(list), [
|
||||
contentData,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
// // Add to Trakt lists that are new
|
||||
// const groupsToAdd = newGroups.filter(
|
||||
// (g) => !prevGroups.includes(g),
|
||||
// );
|
||||
// for (const groupName of groupsToAdd) {
|
||||
// const list = await ensureListExists(slug!, groupName);
|
||||
// if (list) {
|
||||
// await traktService.addToList(slug!, listId(list), [
|
||||
// contentData,
|
||||
// ]);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
} else if (item.action === "delete") {
|
||||
await traktService.removeFromWatchlist(contentData);
|
||||
if (hasLists && item.group?.length) {
|
||||
for (const groupName of item.group) {
|
||||
const list = await findListByName(slug!, groupName);
|
||||
if (list) {
|
||||
await traktService.removeFromList(slug!, listId(list), [
|
||||
contentData,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Collections sync disabled - bookmarks only sync to watchlist
|
||||
// if (hasLists && item.group?.length) {
|
||||
// for (const groupName of item.group) {
|
||||
// const list = await findListByName(slug!, groupName);
|
||||
// if (list) {
|
||||
// await traktService.removeFromList(slug!, listId(list), [
|
||||
// contentData,
|
||||
// ]);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to sync bookmark to Trakt", error);
|
||||
|
|
@ -120,19 +119,20 @@ export function TraktBookmarkSyncer() {
|
|||
};
|
||||
|
||||
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 () => {
|
||||
if (!accessToken || isSyncingRef.current) return;
|
||||
const slug = useTraktAuthStore.getState().user?.ids?.slug;
|
||||
if (!slug) return;
|
||||
// const slug = useTraktAuthStore.getState().user?.ids?.slug;
|
||||
// if (!slug) return;
|
||||
isSyncingRef.current = true;
|
||||
try {
|
||||
if (!useTraktAuthStore.getState().user) {
|
||||
await traktService.getUserProfile();
|
||||
}
|
||||
const bookmarks = useBookmarkStore.getState().bookmarks;
|
||||
|
||||
for (const [tmdbId, b] of Object.entries(bookmarks)) {
|
||||
try {
|
||||
const contentData: TraktContentData = {
|
||||
|
|
@ -142,14 +142,15 @@ export function TraktBookmarkSyncer() {
|
|||
type: b.type === "movie" ? "movie" : "show",
|
||||
};
|
||||
await traktService.addToWatchlist(contentData);
|
||||
if (b.group?.length) {
|
||||
for (const groupName of b.group) {
|
||||
const list = await ensureListExists(slug, groupName);
|
||||
if (list) {
|
||||
await traktService.addToList(slug, listId(list), [contentData]);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Collections sync disabled - bookmarks only sync to watchlist
|
||||
// if (b.group?.length) {
|
||||
// for (const groupName of b.group) {
|
||||
// const list = await ensureListExists(slug, groupName);
|
||||
// if (list) {
|
||||
// await traktService.addToList(slug, listId(list), [contentData]);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
} catch (err) {
|
||||
console.warn("Failed to push bookmark to Trakt:", tmdbId, err);
|
||||
}
|
||||
|
|
@ -192,63 +193,64 @@ export function TraktBookmarkSyncer() {
|
|||
|
||||
replaceBookmarks(merged);
|
||||
|
||||
const slug = useTraktAuthStore.getState().user?.ids?.slug;
|
||||
if (slug) {
|
||||
try {
|
||||
const lists = await traktService.getLists(slug);
|
||||
const currentBookmarks = useBookmarkStore.getState().bookmarks;
|
||||
let modifiedBookmarks = { ...currentBookmarks };
|
||||
// Collections sync disabled - only watchlist is synced, no Trakt lists
|
||||
// const slug = useTraktAuthStore.getState().user?.ids?.slug;
|
||||
// if (slug) {
|
||||
// try {
|
||||
// const lists = await traktService.getLists(slug);
|
||||
// const currentBookmarks = useBookmarkStore.getState().bookmarks;
|
||||
// let modifiedBookmarks = { ...currentBookmarks };
|
||||
|
||||
for (const list of lists) {
|
||||
const listTitle = list.name;
|
||||
const items = await traktService.getListItems(slug, listId(list));
|
||||
for (const li of items) {
|
||||
const media = li.movie || li.show;
|
||||
if (!media?.ids?.tmdb) continue;
|
||||
// for (const list of lists) {
|
||||
// const listTitle = list.name;
|
||||
// const items = await traktService.getListItems(slug, listId(list));
|
||||
// for (const li of items) {
|
||||
// const media = li.movie || li.show;
|
||||
// if (!media?.ids?.tmdb) continue;
|
||||
|
||||
const tmdbId = media.ids.tmdb.toString();
|
||||
const type = li.movie ? "movie" : "show";
|
||||
const bookmark = modifiedBookmarks[tmdbId];
|
||||
// const tmdbId = media.ids.tmdb.toString();
|
||||
// const type = li.movie ? "movie" : "show";
|
||||
// const bookmark = modifiedBookmarks[tmdbId];
|
||||
|
||||
if (!bookmark) {
|
||||
const poster = await getPosterForMedia(tmdbId, type);
|
||||
modifiedBookmarks[tmdbId] = {
|
||||
type: type as "movie" | "show",
|
||||
title: media.title,
|
||||
year: media.year,
|
||||
poster,
|
||||
updatedAt: Date.now(),
|
||||
group: [listTitle],
|
||||
};
|
||||
} else {
|
||||
const groups = bookmark.group ?? [];
|
||||
if (!groups.includes(listTitle)) {
|
||||
const { modifiedBookmarks: next } = modifyBookmarks(
|
||||
modifiedBookmarks,
|
||||
[tmdbId],
|
||||
{ addGroups: [listTitle] },
|
||||
);
|
||||
modifiedBookmarks = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// if (!bookmark) {
|
||||
// const poster = await getPosterForMedia(tmdbId, type);
|
||||
// modifiedBookmarks[tmdbId] = {
|
||||
// type: type as "movie" | "show",
|
||||
// title: media.title,
|
||||
// year: media.year,
|
||||
// poster,
|
||||
// updatedAt: Date.now(),
|
||||
// group: [listTitle],
|
||||
// };
|
||||
// } else {
|
||||
// const groups = bookmark.group ?? [];
|
||||
// if (!groups.includes(listTitle)) {
|
||||
// const { modifiedBookmarks: next } = modifyBookmarks(
|
||||
// modifiedBookmarks,
|
||||
// [tmdbId],
|
||||
// { addGroups: [listTitle] },
|
||||
// );
|
||||
// modifiedBookmarks = next;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
const hasNewBookmarks =
|
||||
Object.keys(modifiedBookmarks).length !==
|
||||
Object.keys(currentBookmarks).length;
|
||||
const hasGroupChanges = Object.keys(modifiedBookmarks).some(
|
||||
(id) =>
|
||||
JSON.stringify(modifiedBookmarks[id]?.group ?? []) !==
|
||||
JSON.stringify(currentBookmarks[id]?.group ?? []),
|
||||
);
|
||||
if (hasNewBookmarks || hasGroupChanges) {
|
||||
replaceBookmarks(modifiedBookmarks);
|
||||
}
|
||||
} catch (listError) {
|
||||
console.warn("Failed to sync Trakt lists (groups)", listError);
|
||||
}
|
||||
}
|
||||
// const hasNewBookmarks =
|
||||
// Object.keys(modifiedBookmarks).length !==
|
||||
// Object.keys(currentBookmarks).length;
|
||||
// const hasGroupChanges = Object.keys(modifiedBookmarks).some(
|
||||
// (id) =>
|
||||
// JSON.stringify(modifiedBookmarks[id]?.group ?? []) !==
|
||||
// JSON.stringify(currentBookmarks[id]?.group ?? []),
|
||||
// );
|
||||
// if (hasNewBookmarks || hasGroupChanges) {
|
||||
// replaceBookmarks(modifiedBookmarks);
|
||||
// }
|
||||
// } catch (listError) {
|
||||
// console.warn("Failed to sync Trakt lists (groups)", listError);
|
||||
// }
|
||||
// }
|
||||
} catch (error) {
|
||||
console.error("Failed to sync Trakt watchlist to local", error);
|
||||
} finally {
|
||||
|
|
@ -257,8 +259,9 @@ export function TraktBookmarkSyncer() {
|
|||
}, [accessToken, replaceBookmarks]);
|
||||
|
||||
const fullSync = useCallback(async () => {
|
||||
await syncWatchlistFromTrakt(); // Pull Trakt → local, merge
|
||||
await syncBookmarksToTrakt(); // Push local → Trakt
|
||||
// Push local → Trakt first so our changes reach Trakt before we pull
|
||||
await syncBookmarksToTrakt();
|
||||
await syncWatchlistFromTrakt(); // Then pull Trakt → local, merge
|
||||
}, [syncWatchlistFromTrakt, syncBookmarksToTrakt]);
|
||||
|
||||
// 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(() => {
|
||||
if (!hydrated || !accessToken) return;
|
||||
syncWatchlistFromTrakt();
|
||||
const t = setTimeout(fullSync, INITIAL_SYNC_DELAY_MS);
|
||||
return () => clearTimeout(t);
|
||||
}, [hydrated, accessToken, syncWatchlistFromTrakt, fullSync]);
|
||||
}, [hydrated, accessToken, fullSync]);
|
||||
|
||||
// Periodic full sync (pull + push)
|
||||
useInterval(fullSync, TRAKT_SYNC_INTERVAL_MS);
|
||||
|
|
|
|||
Loading…
Reference in a new issue