added chapters on player using aniskip api

This commit is contained in:
2025-12-20 19:56:15 +01:00
parent cbacf2ea07
commit 9943c5d010
4 changed files with 650 additions and 109 deletions

View File

@@ -7,6 +7,10 @@ let currentExtension = '';
let plyrInstance;
let hlsInstance;
let totalEpisodes = 0;
let aniSkipData = null;
let isAnilist = false;
let malId = null;
const params = new URLSearchParams(window.location.search);
const firstKey = params.keys().next().value;
@@ -20,6 +24,18 @@ const href = extName
document.getElementById('back-link').href = href;
document.getElementById('episode-label').innerText = `Episode ${currentEpisode}`;
async function loadAniSkip(malId, episode, duration) {
try {
const res = await fetch(`https://api.aniskip.com/v2/skip-times/${malId}/${episode}?types[]=op&types[]=ed&episodeLength=${duration}`);
if (!res.ok) return null;
const data = await res.json();
return data.results || [];
} catch (error) {
console.error('Error loading AniSkip data:', error);
return null;
}
}
async function loadMetadata() {
try {
const extQuery = extName ? `?source=${extName}` : "?source=anilist";
@@ -40,11 +56,8 @@ async function loadMetadata() {
let format = '';
let seasonYear = '';
let season = '';
let episodesCount = 0;
let characters = [];
if (isAnilistFormat) {
title = data.title.romaji || data.title.english || data.title.native || 'Anime Title';
description = data.description || 'No description available.';
coverImage = data.coverImage?.large || data.coverImage?.medium || '';
@@ -62,6 +75,14 @@ async function loadMetadata() {
seasonYear = data.year || '';
}
if (isAnilistFormat && data.idMal) {
isAnilist = true;
malId = data.idMal;
} else {
isAnilist = false;
malId = null;
}
document.getElementById('anime-title-details').innerText = title;
document.getElementById('anime-title-details2').innerText = title;
document.title = `Watching ${title} - Ep ${currentEpisode}`;
@@ -106,6 +127,102 @@ async function loadMetadata() {
}
}
async function applyAniSkip(video) {
if (!isAnilist || !malId) {
console.log('AniSkip disabled: isAnilist=' + isAnilist + ', malId=' + malId);
return;
}
console.log('Loading AniSkip for MAL ID:', malId, 'Episode:', currentEpisode);
aniSkipData = await loadAniSkip(
malId,
currentEpisode,
Math.floor(video.duration)
);
console.log('AniSkip data received:', aniSkipData);
if (!aniSkipData || aniSkipData.length === 0) {
console.log('No AniSkip data available');
return;
}
let op, ed;
const markers = [];
aniSkipData.forEach(item => {
const { startTime, endTime } = item.interval;
if (item.skipType === 'op') {
op = { start: startTime, end: endTime };
markers.push({
start: startTime,
end: endTime,
label: 'Opening'
});
console.log('Opening found:', startTime, '-', endTime);
}
if (item.skipType === 'ed') {
ed = { start: startTime, end: endTime };
markers.push({
start: startTime,
end: endTime,
label: 'Ending'
});
console.log('Ending found:', startTime, '-', endTime);
}
});
// Crear markers visuales en el DOM
if (plyrInstance && markers.length > 0) {
console.log('Creating visual markers:', markers);
// Esperar a que el player esté completamente cargado
setTimeout(() => {
const progressContainer = document.querySelector('.plyr__progress');
if (!progressContainer) {
console.error('Progress container not found');
return;
}
// Eliminar markers anteriores si existen
const oldMarkers = progressContainer.querySelector('.plyr__markers');
if (oldMarkers) oldMarkers.remove();
// Crear contenedor de markers
const markersContainer = document.createElement('div');
markersContainer.className = 'plyr__markers';
markers.forEach(marker => {
const markerElement = document.createElement('div');
markerElement.className = 'plyr__marker';
markerElement.dataset.label = marker.label;
const startPercent = (marker.start / video.duration) * 100;
const widthPercent = ((marker.end - marker.start) / video.duration) * 100;
markerElement.style.left = `${startPercent}%`;
markerElement.style.width = `${widthPercent}%`;
markerElement.addEventListener('click', (e) => {
e.stopPropagation();
video.currentTime = marker.start;
});
markersContainer.appendChild(markerElement);
});
progressContainer.appendChild(markersContainer);
console.log('Visual markers created successfully');
}, 500);
}
}
async function loadExtensionEpisodes() {
try {
const extQuery = extName ? `?source=${extName}` : "?source=anilist";
@@ -117,7 +234,6 @@ async function loadExtensionEpisodes() {
if (Array.isArray(data) && data.length > 0) {
populateEpisodeCarousel(data);
} else {
const fallback = [];
for (let i = 1; i <= totalEpisodes; i++) {
fallback.push({ number: i, title: null, thumbnail: null });
@@ -132,6 +248,8 @@ async function loadExtensionEpisodes() {
function populateEpisodeCarousel(episodesData) {
const carousel = document.getElementById('episode-carousel');
if (!carousel) return;
carousel.innerHTML = '';
episodesData.forEach((ep, index) => {
@@ -319,9 +437,8 @@ function playVideo(url, subtitles = []) {
if (plyrInstance) plyrInstance.destroy();
while (video.textTracks.length > 0) {
video.removeChild(video.textTracks[0]);
}
const existingTracks = video.querySelectorAll('track');
existingTracks.forEach(track => track.remove());
subtitles.forEach(sub => {
if (!sub.url) return;
@@ -337,7 +454,15 @@ function playVideo(url, subtitles = []) {
plyrInstance = new Plyr(video, {
captions: { active: true, update: true, language: 'en' },
controls: ['play-large', 'play', 'progress', 'current-time', 'duration', 'mute', 'volume', 'captions', 'settings', 'pip', 'airplay', 'fullscreen'],
settings: ['captions', 'quality', 'speed']
settings: ['captions', 'quality', 'speed'],
markers: {
enabled: true,
points: []
}
});
video.addEventListener('loadedmetadata', () => {
applyAniSkip(video);
});
let alreadyTriggered = false;
@@ -353,7 +478,6 @@ function playVideo(url, subtitles = []) {
}
});
video.play().catch(() => console.log("Autoplay blocked"));
}
@@ -382,7 +506,6 @@ if (currentEpisode <= 1) {
document.getElementById('prev-btn').disabled = true;
}
async function sendProgress() {
const token = localStorage.getItem('token');
if (!token) return;
@@ -415,7 +538,5 @@ async function sendProgress() {
}
}
loadMetadata();
loadExtensions();
loadExtensions();