From 871ff98bec4a59084c780b2f37afb6a45cba52be Mon Sep 17 00:00:00 2001 From: Akamaru Date: Fri, 3 Oct 2025 20:57:04 +0200 Subject: [PATCH] =?UTF-8?q?Fix=20f=C3=BCr=20Bulk-l=C3=B6schen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- anime-loads-bulk-delete-history.user.js | 302 ++++++++++++++++-------- 1 file changed, 197 insertions(+), 105 deletions(-) diff --git a/anime-loads-bulk-delete-history.user.js b/anime-loads-bulk-delete-history.user.js index b21da33..3286223 100644 --- a/anime-loads-bulk-delete-history.user.js +++ b/anime-loads-bulk-delete-history.user.js @@ -1,7 +1,7 @@ // ==UserScript== // @name Anime-Loads: Verlauf-Massenlöschung // @namespace https://git.ponywave.de/Akamaru/Userscripts -// @version 1.1 +// @version 1.2 // @description Fügt Buttons hinzu, um Verlaufseinträge auf anime-loads.org schneller zu löschen // @author Akamaru // @match https://www.anime-loads.org/history* @@ -21,6 +21,9 @@ } function init() { + // Prüfe ob Bulk-Delete läuft + checkAndContinueBulkDelete(); + const historyDiv = document.getElementById('history'); if (!historyDiv) return; @@ -55,13 +58,6 @@ updateCounter(); }; - // Button: Alle Seiten laden - const loadAllBtn = document.createElement('button'); - loadAllBtn.textContent = 'Alle Seiten laden'; - loadAllBtn.className = 'btn btn-info'; - loadAllBtn.id = 'load-all-pages-btn'; - loadAllBtn.onclick = loadAllPages; - // Zähler für ausgewählte Einträge const counterSpan = document.createElement('span'); counterSpan.id = 'selection-counter'; @@ -71,7 +67,6 @@ buttonContainer.appendChild(deleteAllBtn); buttonContainer.appendChild(deleteSelectedBtn); buttonContainer.appendChild(toggleAllBtn); - buttonContainer.appendChild(loadAllBtn); buttonContainer.appendChild(counterSpan); // Füge Button-Container vor dem History-Div ein @@ -158,12 +153,194 @@ } function deleteAll() { + showDeleteOptionsModal(); + } + + function showDeleteOptionsModal() { + // Erstelle Modal-Overlay + const overlay = document.createElement('div'); + overlay.style.cssText = 'position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); z-index: 9999; display: flex; align-items: center; justify-content: center;'; + + // Erstelle Modal-Content + const modal = document.createElement('div'); + modal.className = 'modal-content'; + modal.style.cssText = 'background: white; padding: 25px; border-radius: 8px; max-width: 500px; box-shadow: 0 4px 6px rgba(0,0,0,0.1);'; + + const title = document.createElement('h3'); + title.textContent = 'Verlauf löschen'; + title.style.cssText = 'margin: 0 0 20px 0;'; + + const optionsDiv = document.createElement('div'); + optionsDiv.style.cssText = 'margin-bottom: 20px;'; + + // Option 1: Aktuelle Seite + const currentPageBtn = document.createElement('button'); + currentPageBtn.textContent = 'Aktuelle Seite löschen'; + currentPageBtn.className = 'btn btn-warning'; + currentPageBtn.style.cssText = 'width: 100%; margin-bottom: 10px;'; + currentPageBtn.onclick = () => { + overlay.remove(); + deleteCurrentPage(); + }; + + // Option 2: Gesamter Verlauf + const allPagesBtn = document.createElement('button'); + allPagesBtn.textContent = 'Gesamten Verlauf löschen'; + allPagesBtn.className = 'btn btn-danger'; + allPagesBtn.style.cssText = 'width: 100%; margin-bottom: 10px;'; + allPagesBtn.onclick = () => { + overlay.remove(); + deleteAllPages(); + }; + + // Option 3: Seite x bis x + const rangeDiv = document.createElement('div'); + rangeDiv.style.cssText = 'display: flex; gap: 10px; align-items: center; margin-bottom: 10px;'; + + const fromInput = document.createElement('input'); + fromInput.type = 'number'; + fromInput.placeholder = 'Von Seite'; + fromInput.className = 'form-control'; + fromInput.style.cssText = 'flex: 1;'; + fromInput.min = '1'; + + const toInput = document.createElement('input'); + toInput.type = 'number'; + toInput.placeholder = 'Bis Seite'; + toInput.className = 'form-control'; + toInput.style.cssText = 'flex: 1;'; + toInput.min = '1'; + + const rangeBtn = document.createElement('button'); + rangeBtn.textContent = 'Löschen'; + rangeBtn.className = 'btn btn-primary'; + rangeBtn.onclick = () => { + const from = parseInt(fromInput.value); + const to = parseInt(toInput.value); + if (from && to && from <= to) { + overlay.remove(); + deletePageRange(from, to); + } else { + alert('Bitte gültige Seitenzahlen eingeben.'); + } + }; + + rangeDiv.appendChild(fromInput); + rangeDiv.appendChild(toInput); + rangeDiv.appendChild(rangeBtn); + + // Abbrechen Button + const cancelBtn = document.createElement('button'); + cancelBtn.textContent = 'Abbrechen'; + cancelBtn.className = 'btn btn-default'; + cancelBtn.style.cssText = 'width: 100%;'; + cancelBtn.onclick = () => overlay.remove(); + + optionsDiv.appendChild(currentPageBtn); + optionsDiv.appendChild(allPagesBtn); + optionsDiv.appendChild(rangeDiv); + optionsDiv.appendChild(cancelBtn); + + modal.appendChild(title); + modal.appendChild(optionsDiv); + overlay.appendChild(modal); + document.body.appendChild(overlay); + + // Schließe Modal bei Klick auf Overlay + overlay.addEventListener('click', (e) => { + if (e.target === overlay) overlay.remove(); + }); + } + + function deleteCurrentPage() { const removeButtons = Array.from(document.querySelectorAll('.remove-history')); - showModal(`Möchtest du wirklich ALLE ${removeButtons.length} Einträge aus dem Verlauf löschen?`, () => { + showModal(`Möchtest du wirklich alle ${removeButtons.length} Einträge auf dieser Seite löschen?`, () => { deleteEntries(removeButtons); }); } + async function deleteAllPages() { + const pagination = document.querySelector('.pagination'); + if (!pagination) { + showModal('Keine Pagination gefunden.', () => {}); + return; + } + + const pageLinks = Array.from(pagination.querySelectorAll('li a')); + const pageNumbers = pageLinks + .map(link => { + const match = link.href.match(/\/page\/(\d+)/); + return match ? parseInt(match[1]) : 0; + }) + .filter(num => num > 0); + + const lastPage = pageNumbers.length > 0 ? Math.max(...pageNumbers) : 1; + + showModal(`Möchtest du wirklich den GESAMTEN Verlauf löschen (${lastPage} Seiten)?`, async () => { + await deletePageRange(1, lastPage); + }); + } + + function deletePageRange(fromPage, toPage) { + // Speichere Lösch-Status in localStorage + localStorage.setItem('bulkDeleteFrom', fromPage); + localStorage.setItem('bulkDeleteTo', toPage); + localStorage.setItem('bulkDeleteCurrent', fromPage); + + // Starte Löschvorgang + const url = fromPage === 1 ? 'https://www.anime-loads.org/history' : `https://www.anime-loads.org/history/page/${fromPage}`; + window.location.href = url; + } + + function checkAndContinueBulkDelete() { + const current = parseInt(localStorage.getItem('bulkDeleteCurrent')); + const to = parseInt(localStorage.getItem('bulkDeleteTo')); + + if (!current || !to) return; + + // Zeige Fortschritt mit Abbrechen-Button + const progress = document.createElement('div'); + progress.style.cssText = 'position: fixed; top: 20px; right: 20px; background: #f0ad4e; color: white; padding: 15px; border-radius: 5px; z-index: 10000; font-weight: bold;'; + + const progressText = document.createElement('div'); + progressText.textContent = `Lösche Seite ${current} von ${to}...`; + progressText.style.marginBottom = '10px'; + + const cancelBtn = document.createElement('button'); + cancelBtn.textContent = 'Abbrechen'; + cancelBtn.className = 'btn btn-sm btn-default'; + cancelBtn.onclick = () => { + localStorage.removeItem('bulkDeleteFrom'); + localStorage.removeItem('bulkDeleteTo'); + localStorage.removeItem('bulkDeleteCurrent'); + window.location.href = 'https://www.anime-loads.org/history'; + }; + + progress.appendChild(progressText); + progress.appendChild(cancelBtn); + document.body.appendChild(progress); + + // Lösche alle Einträge auf der aktuellen Seite + const removeButtons = Array.from(document.querySelectorAll('.remove-history')); + removeButtons.forEach(btn => btn.click()); + + // Warte, dann gehe zur nächsten Seite + setTimeout(() => { + if (current < to) { + const nextPage = current + 1; + localStorage.setItem('bulkDeleteCurrent', nextPage); + const url = nextPage === 1 ? 'https://www.anime-loads.org/history' : `https://www.anime-loads.org/history/page/${nextPage}`; + window.location.href = url; + } else { + // Fertig - lösche Status + localStorage.removeItem('bulkDeleteFrom'); + localStorage.removeItem('bulkDeleteTo'); + localStorage.removeItem('bulkDeleteCurrent'); + window.location.href = 'https://www.anime-loads.org/history'; + } + }, 2000); + } + function deleteSelected() { const checkboxes = Array.from(document.querySelectorAll('.bulk-delete-checkbox:checked')); if (checkboxes.length === 0) { @@ -178,109 +355,24 @@ } function deleteEntries(buttons) { - let deleted = 0; + let processed = 0; const total = buttons.length; buttons.forEach((btn, index) => { setTimeout(() => { - btn.click(); - deleted++; + // Prüfe ob Button noch im DOM existiert + if (document.body.contains(btn)) { + btn.click(); + } + processed++; - if (deleted === total) { + if (processed === total) { setTimeout(() => { - // Seite neu laden oder Checkboxen neu hinzufügen + // Seite neu laden location.reload(); - }, 500); + }, 1000); // Längere Wartezeit für alle Lösch-Requests } - }, index * 200); // 200ms Verzögerung zwischen jedem Klick - }); - } - - async function loadAllPages() { - const btn = document.getElementById('load-all-pages-btn'); - const pagination = document.querySelector('.pagination'); - - if (!pagination) { - showModal('Keine Pagination gefunden.', () => {}); - return; - } - - // Finde die letzte Seitenzahl - const pageLinks = Array.from(pagination.querySelectorAll('li a')); - const pageNumbers = pageLinks - .map(link => { - const match = link.href.match(/\/page\/(\d+)/); - return match ? parseInt(match[1]) : 0; - }) - .filter(num => num > 0); - - if (pageNumbers.length === 0) { - showModal('Konnte letzte Seite nicht ermitteln.', () => {}); - return; - } - - const lastPage = Math.max(...pageNumbers); - const currentPage = parseInt(window.location.pathname.match(/\/page\/(\d+)/)?.[1] || 1); - - if (currentPage !== 1) { - showModal('Bitte gehe zuerst zur ersten Seite.', () => {}); - return; - } - - showModal(`Möchtest du ${lastPage - 1} weitere Seiten laden? Dies kann eine Weile dauern.`, async () => { - btn.disabled = true; - btn.textContent = 'Lade Seiten...'; - - const historyDiv = document.getElementById('history'); - const table = historyDiv.querySelector('table tbody'); - - for (let page = 2; page <= lastPage; page++) { - try { - btn.textContent = `Lade Seite ${page}/${lastPage}...`; - - const response = await fetch(`https://www.anime-loads.org/history/page/${page}`); - const html = await response.text(); - - const parser = new DOMParser(); - const doc = parser.parseFromString(html, 'text/html'); - const newRows = doc.querySelectorAll('#history table tbody tr'); - - newRows.forEach(row => { - const clonedRow = row.cloneNode(true); - table.appendChild(clonedRow); - - // Checkbox sofort zum geklonten Row hinzufügen - const removeBtn = clonedRow.querySelector('.remove-history'); - if (removeBtn && !clonedRow.querySelector('.bulk-delete-checkbox')) { - const checkbox = document.createElement('input'); - checkbox.type = 'checkbox'; - checkbox.className = 'bulk-delete-checkbox'; - checkbox.style.cssText = 'margin-right: 10px; transform: scale(1.3);'; - checkbox.addEventListener('change', updateCounter); - - const td = removeBtn.closest('td'); - td.insertBefore(checkbox, td.firstChild); - } - }); - - // Counter nach jeder Seite aktualisieren - updateCounter(); - - // Kleine Verzögerung, um Server nicht zu überlasten - await new Promise(resolve => setTimeout(resolve, 500)); - } catch (error) { - console.error(`Fehler beim Laden von Seite ${page}:`, error); - } - } - - // Pagination verstecken - pagination.style.display = 'none'; - - btn.textContent = 'Alle Seiten geladen!'; - setTimeout(() => { - btn.textContent = 'Alle Seiten laden'; - btn.disabled = false; - }, 3000); + }, index * 300); // Längere Verzögerung zwischen Klicks }); } })();