added manual matching on books
This commit is contained in:
@@ -23,7 +23,6 @@ const AnimePlayer = (function() {
|
||||
let hlsInstance = null;
|
||||
|
||||
let _manualExtensionId = null;
|
||||
let _searchTimeout = null;
|
||||
|
||||
const els = {
|
||||
wrapper: null,
|
||||
@@ -46,10 +45,6 @@ const AnimePlayer = (function() {
|
||||
dlConfirmBtn: null,
|
||||
dlCancelBtn: null,
|
||||
manualMatchBtn: null,
|
||||
matchModal: null,
|
||||
matchInput: null,
|
||||
matchList: null,
|
||||
closeMatchModalBtn: null
|
||||
};
|
||||
|
||||
function init(animeId, initialSource, isLocal, animeData) {
|
||||
@@ -83,31 +78,6 @@ const AnimePlayer = (function() {
|
||||
els.dlConfirmBtn = document.getElementById('confirm-dl-btn');
|
||||
els.dlCancelBtn = document.getElementById('cancel-dl-btn');
|
||||
els.manualMatchBtn = document.getElementById('manual-match-btn');
|
||||
els.matchModal = document.getElementById('match-modal');
|
||||
els.matchInput = document.getElementById('match-search-input');
|
||||
els.matchList = document.getElementById('match-results-list');
|
||||
els.closeMatchModalBtn = document.getElementById('close-match-modal');
|
||||
|
||||
// Event Listeners para Manual Match
|
||||
if (els.manualMatchBtn) els.manualMatchBtn.addEventListener('click', openMatchModal);
|
||||
if (els.closeMatchModalBtn) els.closeMatchModalBtn.addEventListener('click', closeMatchModal);
|
||||
|
||||
// Cerrar modal al hacer click fuera
|
||||
if (els.matchModal) {
|
||||
els.matchModal.addEventListener('click', (e) => {
|
||||
if (e.target === els.matchModal) closeMatchModal();
|
||||
});
|
||||
}
|
||||
|
||||
// Input de búsqueda con Debounce
|
||||
if (els.matchInput) {
|
||||
els.matchInput.addEventListener('input', (e) => {
|
||||
clearTimeout(_searchTimeout);
|
||||
_searchTimeout = setTimeout(() => {
|
||||
executeMatchSearch(e.target.value);
|
||||
}, 500); // Esperar 500ms tras dejar de escribir
|
||||
});
|
||||
}
|
||||
|
||||
const closeDlModalBtn = document.getElementById('close-download-modal');
|
||||
|
||||
@@ -168,112 +138,33 @@ const AnimePlayer = (function() {
|
||||
if(els.subDubToggle) els.subDubToggle.addEventListener('click', toggleAudioMode);
|
||||
if(els.serverSelect) els.serverSelect.addEventListener('change', () => loadStream());
|
||||
if(els.extSelect) els.extSelect.addEventListener('change', () => handleExtensionChange(true));
|
||||
if (els.manualMatchBtn) {
|
||||
els.manualMatchBtn.addEventListener('click', openMatchModal);
|
||||
}
|
||||
|
||||
loadExtensionsList();
|
||||
}
|
||||
|
||||
function openMatchModal() {
|
||||
if (!els.matchModal) return;
|
||||
const currentExt = els.extSelect.value;
|
||||
if (!currentExt || currentExt === 'local') return;
|
||||
|
||||
// Limpiar contenido previo
|
||||
els.matchInput.value = '';
|
||||
els.matchList.innerHTML = `<div style="padding:20px; text-align:center; color:#777;">Type to search in ${els.extSelect.value}...</div>`;
|
||||
|
||||
// 1. Mostrar el contenedor (para que el navegador calcule el layout)
|
||||
els.matchModal.style.display = 'flex';
|
||||
|
||||
// 2. Pequeño delay o forzar reflow para que la transición de opacidad funcione
|
||||
requestAnimationFrame(() => {
|
||||
els.matchModal.classList.add('show');
|
||||
});
|
||||
|
||||
setTimeout(() => els.matchInput.focus(), 100);
|
||||
}
|
||||
|
||||
function closeMatchModal() {
|
||||
if (!els.matchModal) return;
|
||||
els.matchModal.classList.remove('show');
|
||||
setTimeout(() => {
|
||||
if (!els.matchModal.classList.contains('show')) {
|
||||
els.matchModal.style.display = 'none';
|
||||
MatchModal.open({
|
||||
provider: currentExt,
|
||||
initialQuery: _animeTitle, // Variable existente en player.js
|
||||
onSearch: async (query, prov) => {
|
||||
const res = await fetch(`/api/search/${prov}?q=${encodeURIComponent(query)}`);
|
||||
const data = await res.json();
|
||||
return data.results || [];
|
||||
},
|
||||
onSelect: (item) => {
|
||||
console.log("Selected Anime ID:", item.id);
|
||||
_manualExtensionId = item.id;
|
||||
loadStream();
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
|
||||
async function executeMatchSearch(query) {
|
||||
if (!query || query.trim().length < 2) return;
|
||||
|
||||
const ext = els.extSelect.value;
|
||||
if (!ext || ext === 'local') return;
|
||||
|
||||
els.matchList.innerHTML = '<div class="spinner" style="margin: 20px auto;"></div>';
|
||||
|
||||
try {
|
||||
const res = await fetch(`/api/search/${ext}?q=${encodeURIComponent(query)}`);
|
||||
const data = await res.json();
|
||||
|
||||
renderMatchResults(data.results || []);
|
||||
} catch (e) {
|
||||
console.error("Match Search Error:", e);
|
||||
els.matchList.innerHTML = '<p style="color:#ef4444; text-align:center;">Error searching extension.</p>';
|
||||
}
|
||||
}
|
||||
|
||||
function renderMatchResults(results) {
|
||||
els.matchList.innerHTML = '';
|
||||
|
||||
if (results.length === 0) {
|
||||
els.matchList.innerHTML = '<p style="text-align:center; color:#999;">No results found.</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
results.forEach(item => {
|
||||
const div = document.createElement('div');
|
||||
div.className = 'match-item dl-item';
|
||||
|
||||
const img = (item.coverImage && item.coverImage.large) ? item.coverImage.large : "/public/assets/placeholder.svg";
|
||||
const title = item.title.english || item.title.romaji || item.title || 'Unknown';
|
||||
const externalUrl = item.url || '#'; // El parámetro URL del JSON
|
||||
|
||||
div.innerHTML = `
|
||||
<img src="${img}" alt="cover">
|
||||
<div class="match-info">
|
||||
<span class="match-title">${title}</span>
|
||||
<span class="match-meta">${item.releaseDate || item.year || ''}</span>
|
||||
</div>
|
||||
${item.url ? `
|
||||
<a href="${externalUrl}" target="_blank" class="btn-view-source" title="View Source">
|
||||
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>
|
||||
<polyline points="15 3 21 3 21 9"></polyline>
|
||||
<line x1="10" y1="14" x2="21" y2="3"></line>
|
||||
</svg>
|
||||
</a>
|
||||
` : ''}
|
||||
`;
|
||||
|
||||
div.onclick = (e) => {
|
||||
if (e.target.closest('.btn-view-source')) return;
|
||||
selectManualMatch(item);
|
||||
};
|
||||
|
||||
els.matchList.appendChild(div);
|
||||
});
|
||||
}
|
||||
|
||||
function selectManualMatch(item) {
|
||||
// 1. Guardar el ID de la extensión
|
||||
_manualExtensionId = item.id;
|
||||
|
||||
console.log("Manual Match Selected:", _manualExtensionId, "for extension:", els.extSelect.value);
|
||||
|
||||
// 2. Cerrar modal
|
||||
closeMatchModal();
|
||||
|
||||
// 3. Recargar el stream con el nuevo ID
|
||||
loadStream();
|
||||
}
|
||||
|
||||
async function openInMPV() {
|
||||
if (!_rawVideoData) {
|
||||
alert("No video loaded yet.");
|
||||
|
||||
Reference in New Issue
Block a user