EpiNeko’s library management system allows users to organize their anime collection across different viewing statuses. The library is built on top of Supabase with row-level security, ensuring each user’s data is private and secure.
Add to Library
Save anime to your collection with a single click
Update Status
Change viewing status as you progress through series
Track Progress
Monitor episodes watched and completion percentage
Remove Items
Clean up your library by removing unwanted entries
import { getLibrary } from '@/services/library';// Get all library items for the current userconst items = await getLibrary();// Items are sorted by most recently updatedconsole.log(`You have ${items.length} anime in your library`);
Returns all items ordered by updated_at descending (src/services/library.ts:63-72).
import { getLibraryItem } from '@/services/library';// Check if a specific anime is in the libraryconst item = await getLibraryItem(52991);if (item) { console.log(`Status: ${item.status}`); console.log(`Progress: ${item.episodes_watched} episodes`);} else { console.log('Not in library');}
Returns null if the item doesn’t exist (src/services/library.ts:74-88).
The LibraryButton component provides a complete interface for managing library items with status dropdown:
import LibraryButton from '@/components/anime/LibraryButton';<LibraryButton animeId={52991} title="Sousou no Frieren" imageUrl="https://cdn.myanimelist.net/images/anime/..."/>
1
Initial State
When not in library, displays ”+ AÑADIR A MI LISTA” button
2
Added State
After adding, shows ”✓ EN MI LISTA” and a status dropdown appears
3
Status Selection
Users can change between watching, completed, plan to watch, and dropped
4
Removal
Clicking the main button when in library removes the item
Status Labels (src/components/anime/LibraryButton.tsx:73-78):
The library page displays all items in a responsive grid layout:
Features
Usage
Responsive grid (2-6 columns based on screen size)
Loading skeletons during data fetch
Empty state with call-to-action
Direct links to anime detail pages
Sorted by most recently updated
// Access at /library route// Automatically displays current user's library// Component: src/app/library/page.tsx// Fetches data using getLibrary()// Renders AnimeCard for each item
The library is backed by a PostgreSQL table with row-level security:
create table public.user_library ( id uuid default gen_random_uuid() primary key, user_id uuid references public.profiles(id) on delete cascade not null, anime_id_jikan integer not null, title text not null, image_url text, status public.library_status default 'watching' not null, score integer check (score >= 0 and score <= 10), episodes_watched integer default 0, created_at timestamp with time zone default timezone('utc'::text, now()) not null, updated_at timestamp with time zone default timezone('utc'::text, now()) not null, unique(user_id, anime_id_jikan));
The unique constraint on (user_id, anime_id_jikan) prevents duplicate entries. Attempting to add the same anime twice will result in a database error.
All library functions properly handle authentication and database errors:
try { await addToLibrary(item);} catch (error) { if (error.message.includes('logged in')) { // User is not authenticated alert('Please log in to add items to your library'); }}