code organisation & refactor

This commit is contained in:
2025-11-27 20:23:00 +01:00
parent 03636fee99
commit 2b29beeeb5
33 changed files with 2099 additions and 1947 deletions

178
src/scripts/anime/anime.js Normal file
View File

@@ -0,0 +1,178 @@
const animeId = window.location.pathname.split('/').pop();
let player;
let totalEpisodes = 0;
let currentPage = 1;
const itemsPerPage = 12;
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
async function loadAnime() {
try {
const res = await fetch(`/api/anime/${animeId}`);
const data = await res.json();
if(data.error) {
document.getElementById('title').innerText = "Anime Not Found";
return;
}
const title = data.title.english || data.title.romaji;
document.title = `${title} | WaifuBoard`;
document.getElementById('title').innerText = title;
document.getElementById('poster').src = data.coverImage.extraLarge;
const rawDesc = data.description || "No description available.";
handleDescription(rawDesc);
document.getElementById('score').innerText = (data.averageScore || '?') + '% Score';
document.getElementById('year').innerText = data.seasonYear || '????';
document.getElementById('genres').innerText = data.genres ? data.genres.slice(0, 3).join(' • ') : '';
document.getElementById('format').innerText = data.format || 'TV';
document.getElementById('episodes').innerText = data.episodes || '?';
document.getElementById('status').innerText = data.status || 'Unknown';
document.getElementById('season').innerText = `${data.season || ''} ${data.seasonYear || ''}`;
if (data.studios && data.studios.nodes.length > 0) {
document.getElementById('studio').innerText = data.studios.nodes[0].name;
}
if (data.characters && data.characters.nodes) {
const charContainer = document.getElementById('char-list');
data.characters.nodes.slice(0, 5).forEach(char => {
charContainer.innerHTML += `
<div class="character-item">
<div class="char-dot"></div> ${char.name.full}
</div>`;
});
}
document.getElementById('watch-btn').onclick = () => {
window.location.href = `/watch/${animeId}/1`;
};
if (data.trailer && data.trailer.site === 'youtube') {
window.onYouTubeIframeAPIReady = function() {
player = new YT.Player('player', {
height: '100%',
width: '100%',
videoId: data.trailer.id,
playerVars: {
'autoplay': 1, 'controls': 0, 'mute': 1,
'loop': 1, 'playlist': data.trailer.id,
'showinfo': 0, 'modestbranding': 1, 'disablekb': 1
},
events: { 'onReady': (e) => e.target.playVideo() }
});
};
} else {
const banner = data.bannerImage || data.coverImage.extraLarge;
document.querySelector('.video-background').innerHTML = `<img src="${banner}" style="width:100%; height:100%; object-fit:cover;">`;
}
if (data.nextAiringEpisode) {
totalEpisodes = data.nextAiringEpisode.episode - 1;
} else {
totalEpisodes = data.episodes || 12;
}
totalEpisodes = Math.min(Math.max(totalEpisodes, 1), 5000);
renderEpisodes();
} catch (err) {
console.error(err);
}
}
function handleDescription(text) {
const tmp = document.createElement("DIV");
tmp.innerHTML = text;
const cleanText = tmp.textContent || tmp.innerText || "";
const sentences = cleanText.match(/[^\.!\?]+[\.!\?]+/g) || [cleanText];
document.getElementById('full-description').innerHTML = text;
if (sentences.length > 4) {
const shortText = sentences.slice(0, 4).join(' ');
document.getElementById('description-preview').innerText = shortText + '...';
document.getElementById('read-more-btn').style.display = 'inline-flex';
} else {
document.getElementById('description-preview').innerHTML = text;
document.getElementById('read-more-btn').style.display = 'none';
}
}
function openModal() {
document.getElementById('desc-modal').classList.add('active');
document.body.style.overflow = 'hidden';
}
function closeModal() {
document.getElementById('desc-modal').classList.remove('active');
document.body.style.overflow = '';
}
document.getElementById('desc-modal').addEventListener('click', (e) => {
if (e.target.id === 'desc-modal') closeModal();
});
function renderEpisodes() {
const grid = document.getElementById('episodes-grid');
grid.innerHTML = '';
const start = (currentPage - 1) * itemsPerPage + 1;
const end = Math.min(start + itemsPerPage - 1, totalEpisodes);
for(let i = start; i <= end; i++) {
createEpisodeButton(i, grid);
}
updatePaginationControls();
}
function createEpisodeButton(num, container) {
const btn = document.createElement('div');
btn.className = 'episode-btn';
btn.innerText = `Ep ${num}`;
btn.onclick = () => window.location.href = `/watch/${animeId}/${num}`;
container.appendChild(btn);
}
function updatePaginationControls() {
const totalPages = Math.ceil(totalEpisodes / itemsPerPage);
document.getElementById('page-info').innerText = `Page ${currentPage} of ${totalPages}`;
document.getElementById('prev-page').disabled = currentPage === 1;
document.getElementById('next-page').disabled = currentPage === totalPages;
document.getElementById('pagination-controls').style.display = 'flex';
}
function changePage(delta) {
currentPage += delta;
renderEpisodes();
}
const searchInput = document.getElementById('ep-search');
searchInput.addEventListener('input', (e) => {
const val = parseInt(e.target.value);
const grid = document.getElementById('episodes-grid');
if (val > 0 && val <= totalEpisodes) {
grid.innerHTML = '';
createEpisodeButton(val, grid);
document.getElementById('pagination-controls').style.display = 'none';
} else if (!e.target.value) {
renderEpisodes();
} else {
grid.innerHTML = '<div style="color:#666; width:100%; text-align:center;">Episode not found</div>';
document.getElementById('pagination-controls').style.display = 'none';
}
});
loadAnime();