diff --git a/src/api/anilist/anilist.service.ts b/src/api/anilist/anilist.service.ts index 7d8e837..670102b 100644 --- a/src/api/anilist/anilist.service.ts +++ b/src/api/anilist/anilist.service.ts @@ -91,38 +91,51 @@ export async function getUserAniList(appUserId: number) { if (!access_token || !anilist_user_id) return []; const query = ` - query ($userId: Int) { - anime: MediaListCollection(userId: $userId, type: ANIME) { - lists { - entries { - mediaId - status - progress - score - startedAt { year month day } - completedAt { year month day } - repeat - notes - private - } - } - } - manga: MediaListCollection(userId: $userId, type: MANGA) { - lists { - entries { - mediaId - status - progress - score - startedAt { year month day } - completedAt { year month day } - repeat - notes - private - } - } + query ($userId: Int) { + anime: MediaListCollection(userId: $userId, type: ANIME) { + lists { + entries { + media { + id + title { romaji english userPreferred } + coverImage { extraLarge } + episodes + nextAiringEpisode { episode } } + status + progress + score + repeat + notes + private + startedAt { year month day } + completedAt { year month day } + } } + } + + manga: MediaListCollection(userId: $userId, type: MANGA) { + lists { + entries { + media { + id + title { romaji english userPreferred } + coverImage { extraLarge } + chapters + volumes + } + status + progress + score + repeat + notes + private + startedAt { year month day } + completedAt { year month day } + } + } + } + } `; const res = await fetchWithRetry('https://graphql.anilist.co', { @@ -138,15 +151,10 @@ export async function getUserAniList(appUserId: number) { }), }); - if (!res.ok) { - throw new Error(`AniList API error: ${res.status}`); - } + if (!res.ok) throw new Error(`AniList API error: ${res.status}`); const json = await res.json(); - - if (json?.errors?.length) { - throw new Error(json.errors[0].message); - } + if (json?.errors?.length) throw new Error(json.errors[0].message); const fromFuzzy = (d: any) => { if (!d?.year) return null; @@ -160,9 +168,24 @@ export async function getUserAniList(appUserId: number) { for (const list of lists || []) { for (const entry of list.entries || []) { + const media = entry.media; + + const totalEpisodes = + media?.episodes || + (media?.nextAiringEpisode?.episode + ? media.nextAiringEpisode.episode - 1 + : 0); + + const totalChapters = + media?.chapters || + (media?.volumes ? media.volumes * 10 : 0); + result.push({ user_id: appUserId, - entry_id: entry.mediaId, + + // ✅ FIX CLAVE + entry_id: media.id, + source: 'anilist', entry_type: type, status: entry.status, @@ -172,7 +195,22 @@ export async function getUserAniList(appUserId: number) { end_date: fromFuzzy(entry.completedAt), repeat_count: entry.repeat || 0, notes: entry.notes || null, - is_private: entry.private ? 1 : 0 + is_private: entry.private ? 1 : 0, + + // ✅ CAMPOS QUE EL FRONTEND NECESITA + title: media?.title?.userPreferred + || media?.title?.english + || media?.title?.romaji + || 'Unknown Title', + + poster: media?.coverImage?.extraLarge + || 'https://placehold.co/400x600?text=No+Cover', + + total_episodes: type === 'ANIME' ? totalEpisodes : undefined, + total_chapters: type === 'MANGA' ? totalChapters : undefined, + + // ✅ PARA ORDER BY EN EL FRONT + updated_at: new Date().toISOString() }); } } @@ -184,6 +222,7 @@ export async function getUserAniList(appUserId: number) { ...normalize(json?.data?.anime?.lists, 'ANIME'), ...normalize(json?.data?.manga?.lists, 'MANGA') ]; + } catch (error) { console.error('Error fetching AniList data:', error); return []; diff --git a/src/api/list/list.service.ts b/src/api/list/list.service.ts index 88736b2..9c98e89 100644 --- a/src/api/list/list.service.ts +++ b/src/api/list/list.service.ts @@ -117,14 +117,12 @@ export async function getUserList(userId: number): Promise { try { const dbList = await queryAll(sql, [userId], USER_DB) as ListEntryData[]; - const connected = await isConnected(userId); - let finalList: ListEntryData[] = [...dbList]; + let finalList: any[] = [...dbList]; if (connected) { const anilistEntries = await aniListService.getUserAniList(userId); - const localWithoutAnilist = dbList.filter( entry => entry.source !== 'anilist' ); @@ -133,42 +131,46 @@ export async function getUserList(userId: number): Promise { } const enrichedListPromises = finalList.map(async (entry) => { + // ✅ Si viene de AniList, ya está completo → NO fetch + if (entry.source === 'anilist') { + let finalTitle = entry.title; + if (typeof finalTitle === 'object' && finalTitle !== null) { + finalTitle = + finalTitle.userPreferred || + finalTitle.english || + finalTitle.romaji || + 'Unknown Title'; + } + + return { + ...entry, + title: finalTitle, + poster: entry.poster || 'https://placehold.co/400x600?text=No+Cover', + }; + } + + // ✅ Solo se hace fetch para fuentes NO AniList let contentDetails: any | null = null; const id = entry.entry_id; - const source = entry.source; const type = entry.entry_type; + const ext = getExtension(entry.source); try { if (type === 'ANIME') { - let anime: any; - - if (source === 'anilist') { - anime = await animeService.getAnimeById(id); - } else { - const ext = getExtension(source); - anime = await animeService.getAnimeInfoExtension(ext, id.toString()); - } + const anime: any = await animeService.getAnimeInfoExtension(ext, id.toString()); contentDetails = { title: anime?.title || 'Unknown Anime Title', - poster: anime?.coverImage?.extraLarge || anime?.image || '', - total_episodes: anime?.episodes || anime?.nextAiringEpisode?.episode - 1 || 0, + poster: anime?.image || '', + total_episodes: anime?.episodes || 0, }; } else if (type === 'MANGA' || type === 'NOVEL') { - let book: any; - - if (source === 'anilist') { - book = await booksService.getBookById(id); - } else { - const ext = getExtension(source); - const result = await booksService.getBookInfoExtension(ext, id.toString()); - book = result || null; - } + const book:any = await booksService.getBookInfoExtension(ext, id.toString()); contentDetails = { title: book?.title || 'Unknown Book Title', - poster: book?.coverImage?.extraLarge || book?.image || '', + poster: book?.image || '', total_chapters: book?.chapters || book?.volumes * 10 || 0, }; } @@ -184,7 +186,11 @@ export async function getUserList(userId: number): Promise { let finalPoster = contentDetails?.poster || 'https://placehold.co/400x600?text=No+Cover'; if (typeof finalTitle === 'object' && finalTitle !== null) { - finalTitle = finalTitle.userPreferred || finalTitle.english || finalTitle.romaji || 'Unknown Title'; + finalTitle = + finalTitle.userPreferred || + finalTitle.english || + finalTitle.romaji || + 'Unknown Title'; } return {