// ==UserScript== // @name Anime-Loads: Verlauf-Massenlöschung // @namespace https://git.ponywave.de/Akamaru/Userscripts // @version 1.1 // @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* // @grant none // @updateURL https://git.ponywave.de/Akamaru/Userscripts/raw/branch/master/anime-loads-bulk-delete-history.user.js // @downloadURL https://git.ponywave.de/Akamaru/Userscripts/raw/branch/master/anime-loads-bulk-delete-history.user.js // ==/UserScript== (function() { 'use strict'; // Warte bis die Seite geladen ist if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } function init() { const historyDiv = document.getElementById('history'); if (!historyDiv) return; // Erstelle Button-Container const buttonContainer = document.createElement('div'); buttonContainer.style.cssText = 'margin-bottom: 15px; padding: 10px; background-color: #f5f5f5; border-radius: 5px;'; // Button: Alle löschen const deleteAllBtn = document.createElement('button'); deleteAllBtn.textContent = 'Alle löschen'; deleteAllBtn.className = 'btn btn-danger'; deleteAllBtn.style.marginRight = '10px'; deleteAllBtn.onclick = deleteAll; // Button: Ausgewählte löschen const deleteSelectedBtn = document.createElement('button'); deleteSelectedBtn.textContent = 'Ausgewählte löschen'; deleteSelectedBtn.className = 'btn btn-warning'; deleteSelectedBtn.style.marginRight = '10px'; deleteSelectedBtn.onclick = deleteSelected; // Button: Alle auswählen/abwählen const toggleAllBtn = document.createElement('button'); toggleAllBtn.textContent = 'Alle auswählen'; toggleAllBtn.className = 'btn btn-primary'; toggleAllBtn.style.marginRight = '10px'; toggleAllBtn.onclick = function() { const checkboxes = historyDiv.querySelectorAll('.bulk-delete-checkbox'); const allChecked = Array.from(checkboxes).every(cb => cb.checked); checkboxes.forEach(cb => cb.checked = !allChecked); toggleAllBtn.textContent = allChecked ? 'Alle auswählen' : 'Alle abwählen'; 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'; counterSpan.style.cssText = 'margin-left: 15px; font-weight: bold; font-size: 16px;'; counterSpan.textContent = 'Ausgewählt: 0'; buttonContainer.appendChild(deleteAllBtn); buttonContainer.appendChild(deleteSelectedBtn); buttonContainer.appendChild(toggleAllBtn); buttonContainer.appendChild(loadAllBtn); buttonContainer.appendChild(counterSpan); // Füge Button-Container vor dem History-Div ein historyDiv.parentNode.insertBefore(buttonContainer, historyDiv); // Füge Checkboxen zu jedem Eintrag hinzu addCheckboxes(); } function updateCounter() { const counter = document.getElementById('selection-counter'); if (!counter) return; const checked = document.querySelectorAll('.bulk-delete-checkbox:checked').length; const total = document.querySelectorAll('.bulk-delete-checkbox').length; counter.textContent = `Ausgewählt: ${checked} / ${total}`; } function addCheckboxes() { const historyDiv = document.getElementById('history'); if (!historyDiv) return; const rows = historyDiv.querySelectorAll('table tbody tr'); rows.forEach(row => { if (row.querySelector('.bulk-delete-checkbox')) return; const removeBtn = row.querySelector('.remove-history'); if (!removeBtn) return; 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); }); updateCounter(); } function showModal(message, onConfirm) { // 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 messageEl = document.createElement('p'); messageEl.textContent = message; messageEl.style.cssText = 'margin: 0 0 20px 0; font-size: 16px;'; const buttonContainer = document.createElement('div'); buttonContainer.style.cssText = 'display: flex; justify-content: flex-end; gap: 10px;'; const cancelBtn = document.createElement('button'); cancelBtn.textContent = 'Abbrechen'; cancelBtn.className = 'btn btn-default'; cancelBtn.onclick = () => overlay.remove(); const confirmBtn = document.createElement('button'); confirmBtn.textContent = 'Bestätigen'; confirmBtn.className = 'btn btn-danger'; confirmBtn.onclick = () => { overlay.remove(); onConfirm(); }; buttonContainer.appendChild(cancelBtn); buttonContainer.appendChild(confirmBtn); modal.appendChild(messageEl); modal.appendChild(buttonContainer); 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 deleteAll() { const removeButtons = Array.from(document.querySelectorAll('.remove-history')); showModal(`Möchtest du wirklich ALLE ${removeButtons.length} Einträge aus dem Verlauf löschen?`, () => { deleteEntries(removeButtons); }); } function deleteSelected() { const checkboxes = Array.from(document.querySelectorAll('.bulk-delete-checkbox:checked')); if (checkboxes.length === 0) { showModal('Bitte wähle mindestens einen Eintrag aus.', () => {}); return; } showModal(`Möchtest du ${checkboxes.length} Einträge aus dem Verlauf löschen?`, () => { const removeButtons = checkboxes.map(cb => cb.closest('td').querySelector('.remove-history')); deleteEntries(removeButtons); }); } function deleteEntries(buttons) { let deleted = 0; const total = buttons.length; buttons.forEach((btn, index) => { setTimeout(() => { btn.click(); deleted++; if (deleted === total) { setTimeout(() => { // Seite neu laden oder Checkboxen neu hinzufügen location.reload(); }, 500); } }, 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); }); } })();