diff --git a/binding.gyp b/binding.gyp deleted file mode 100644 index 9f4d3b3..0000000 --- a/binding.gyp +++ /dev/null @@ -1,14 +0,0 @@ -{ - "targets": [ - { - "target_name": "anime_core", - "cflags!": [ "-fno-exceptions" ], - "cflags_cc!": [ "-fno-exceptions" ], - "sources": [ "./src/main.cpp" ], - "include_dirs": [ - " { - await loadList(); - setupEventListeners(); +document.addEventListener('DOMContentLoaded', () => { + SearchManager.init('#search-input', '#search-results', 'anime'); + ContinueWatchingManager.load('my-status', 'watching', 'ANIME'); + fetchContent(); + setInterval(() => fetchContent(true), 60000); }); -function getEntryLink(item) { - const isAnime = item.entry_type?.toUpperCase() === 'ANIME'; - const baseRoute = isAnime ? '/anime' : '/book'; - const source = item.source || 'anilist'; +document.addEventListener('click', (e) => { + if (!e.target.closest('.search-wrapper')) { + const searchResults = document.getElementById('search-results'); + const searchInput = document.getElementById('search-input'); + searchResults.classList.remove('active'); + searchInput.style.borderRadius = '99px'; + } +}); - if (source === 'anilist') { - return `${baseRoute}/${item.entry_id}`; - } else { - return `${baseRoute}/${source}/${item.entry_id}`; +function scrollCarousel(id, direction) { + const container = document.getElementById(id); + if(container) { + const scrollAmount = container.clientWidth * 0.75; + container.scrollBy({ left: direction * scrollAmount, behavior: 'smooth' }); } } -async function populateSourceFilter() { - const select = document.getElementById('source-filter'); - if (!select) return; +var tag = document.createElement('script'); +tag.src = "https://www.youtube.com/iframe_api"; +var firstScriptTag = document.getElementsByTagName('script')[0]; +firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); - select.innerHTML = ` - - - `; - - try { - const response = await fetch(`${API_BASE}/extensions`); - if (response.ok) { - const data = await response.json(); - const extensions = data.extensions || []; - - extensions.forEach(extName => { - if (extName.toLowerCase() !== 'anilist' && extName.toLowerCase() !== 'local') { - const option = document.createElement('option'); - option.value = extName; - option.textContent = extName.charAt(0).toUpperCase() + extName.slice(1); - select.appendChild(option); - } - }); - } - } catch (error) { - console.error('Error loading extensions:', error); - } -} - -function setupEventListeners() { - - document.querySelectorAll('.view-btn').forEach(btn => { - btn.addEventListener('click', () => { - document.querySelectorAll('.view-btn').forEach(b => b.classList.remove('active')); - btn.classList.add('active'); - const view = btn.dataset.view; - const container = document.getElementById('list-container'); - if (view === 'list') { - container.classList.add('list-view'); - } else { - container.classList.remove('list-view'); +function onYouTubeIframeAPIReady() { + player = new YT.Player('player', { + height: '100%', + width: '100%', + playerVars: { + 'autoplay': 1, + 'controls': 0, + 'mute': 1, + 'loop': 1, + 'showinfo': 0, + 'modestbranding': 1 + }, + events: { + 'onReady': (e) => { + e.target.mute(); + if(trendingAnimes.length) updateHeroVideo(trendingAnimes[currentHeroIndex]); } - }); - }); - - document.getElementById('status-filter').addEventListener('change', applyFilters); - document.getElementById('source-filter').addEventListener('change', applyFilters); - document.getElementById('type-filter').addEventListener('change', applyFilters); - document.getElementById('sort-filter').addEventListener('change', applyFilters); - - document.querySelector('.search-input').addEventListener('input', (e) => { - const query = e.target.value.toLowerCase(); - if (query) { - filteredList = currentList.filter(item => - item.title?.toLowerCase().includes(query) - ); - } else { - filteredList = [...currentList]; - } - applyFilters(); - }); - - document.getElementById('modal-save-btn')?.addEventListener('click', async () => { - - const entryToSave = window.ListModalManager.currentEntry || window.ListModalManager.currentData; - - if (!entryToSave) return; - - await window.ListModalManager.save(entryToSave.entry_id, entryToSave.source); - - await loadList(); - }); - - document.getElementById('modal-delete-btn')?.addEventListener('click', async () => { - const entryToDelete = window.ListModalManager.currentEntry || window.ListModalManager.currentData; - - if (!entryToDelete) return; - - await window.ListModalManager.delete(entryToDelete.entry_id, entryToDelete.source); - - await loadList(); - }); - - document.getElementById('add-list-modal')?.addEventListener('click', (e) => { - if (e.target.id === 'add-list-modal') { - window.ListModalManager.close(); } }); } -async function loadList() { - const loadingState = document.getElementById('loading-state'); - const emptyState = document.getElementById('empty-state'); - const container = document.getElementById('list-container'); - - await populateSourceFilter(); - +async function fetchContent(isUpdate = false) { try { - loadingState.style.display = 'flex'; - emptyState.style.display = 'none'; - container.innerHTML = ''; + const trendingRes = await fetch('/api/trending'); + const trendingData = await trendingRes.json(); - const response = await fetch(`${API_BASE}/list`, { - headers: window.AuthUtils.getSimpleAuthHeaders() - }); - - if (!response.ok) { - throw new Error('Failed to load list'); + if (trendingData.results && trendingData.results.length > 0) { + trendingAnimes = trendingData.results; + if (!isUpdate) { + updateHeroUI(trendingAnimes[0]); + startHeroCycle(); + } + renderList('trending', trendingAnimes); + } else if (!isUpdate) { + setTimeout(() => fetchContent(false), 2000); } - const data = await response.json(); - currentList = data.results || []; - filteredList = [...currentList]; - - loadingState.style.display = 'none'; - - if (currentList.length === 0) { - emptyState.style.display = 'flex'; - } else { - updateStats(); - applyFilters(); - } - } catch (error) { - console.error('Error loading list:', error); - loadingState.style.display = 'none'; - if (window.NotificationUtils) { - window.NotificationUtils.error('Failed to load your list. Please try again.'); - } else { - alert('Failed to load your list. Please try again.'); + const topRes = await fetch('/api/top-airing'); + const topData = await topRes.json(); + if (topData.results && topData.results.length > 0) { + renderList('top-airing', topData.results); } + } catch (e) { + console.error("Fetch Error:", e); + if(!isUpdate) setTimeout(() => fetchContent(false), 5000); } } -function updateStats() { - const total = currentList.length; - const watching = currentList.filter(item => item.status === 'WATCHING').length; - const completed = currentList.filter(item => item.status === 'COMPLETED').length; - const planning = currentList.filter(item => item.status === 'PLANNING').length; - - document.getElementById('total-count').textContent = total; - document.getElementById('watching-count').textContent = watching; - document.getElementById('completed-count').textContent = completed; - document.getElementById('planned-count').textContent = planning; +function startHeroCycle() { + if(heroInterval) clearInterval(heroInterval); + heroInterval = setInterval(() => { + if(trendingAnimes.length > 0) { + currentHeroIndex = (currentHeroIndex + 1) % trendingAnimes.length; + updateHeroUI(trendingAnimes[currentHeroIndex]); + } + }, 10000); } -function applyFilters() { - const statusFilter = document.getElementById('status-filter').value; - const sourceFilter = document.getElementById('source-filter').value; - const typeFilter = document.getElementById('type-filter').value; - const sortFilter = document.getElementById('sort-filter').value; +async function updateHeroUI(anime) { + if(!anime) return; - let filtered = [...filteredList]; + const title = anime.title.english || anime.title.romaji || "Unknown Title"; + const score = anime.averageScore ? anime.averageScore + '% Match' : 'N/A'; + const year = anime.seasonYear || ''; + const type = anime.format || 'TV'; + const desc = anime.description || 'No description available.'; + const poster = anime.coverImage ? anime.coverImage.extraLarge : ''; + const banner = anime.bannerImage || poster; - if (statusFilter !== 'all') { - filtered = filtered.filter(item => item.status === statusFilter); + document.getElementById('hero-title').innerText = title; + document.getElementById('hero-desc').innerHTML = desc; + document.getElementById('hero-score').innerText = score; + document.getElementById('hero-year').innerText = year; + document.getElementById('hero-type').innerText = type; + document.getElementById('hero-poster').src = poster; + + const watchBtn = document.getElementById('watch-btn'); + if(watchBtn) watchBtn.onclick = () => window.location.href = `/anime/${anime.id}`; + + const addToListBtn = document.querySelector('.hero-buttons .btn-blur'); + if(addToListBtn) { + ListModalManager.currentData = anime; + const entryType = ListModalManager.getEntryType(anime); + + await ListModalManager.checkIfInList(anime.id, 'anilist', entryType); + ListModalManager.updateButton(); + + addToListBtn.onclick = () => ListModalManager.open(anime, 'anilist'); } - if (sourceFilter !== 'all') { - filtered = filtered.filter(item => item.source === sourceFilter); - } + const bgImg = document.getElementById('hero-bg-media'); + if(bgImg && bgImg.src !== banner) bgImg.src = banner; - if (typeFilter !== 'all') { - filtered = filtered.filter(item => item.entry_type === typeFilter); - } + updateHeroVideo(anime); - switch (sortFilter) { - case 'title': - filtered.sort((a, b) => (a.title || '').localeCompare(b.title || '')); - break; - case 'score': - filtered.sort((a, b) => (b.score || 0) - (a.score || 0)); - break; - case 'progress': - filtered.sort((a, b) => (b.progress || 0) - (a.progress || 0)); - break; - case 'updated': - default: - filtered.sort((a, b) => new Date(b.updated_at) - new Date(a.updated_at)); - break; - } - - renderList(filtered); + document.getElementById('hero-loading-ui').style.display = 'none'; + document.getElementById('hero-real-ui').style.display = 'block'; } -function renderList(items) { - const container = document.getElementById('list-container'); - container.innerHTML = ''; +function updateHeroVideo(anime) { + if (!player || !player.loadVideoById) return; + const videoContainer = document.getElementById('player'); + if (anime.trailer && anime.trailer.site === 'youtube' && anime.trailer.id) { + if(player.getVideoData && player.getVideoData().video_id !== anime.trailer.id) { + player.loadVideoById(anime.trailer.id); + player.mute(); + } + videoContainer.style.opacity = "1"; + } else { + videoContainer.style.opacity = "0"; + player.stopVideo(); + } +} - if (items.length === 0) { - container.innerHTML = '
No entries match your filters
${score}% • ${ep}
+