您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
Enhanced GUI for aniworld.to and s.to websites, allowing you to effortlessly choose your preferred video host and have it automatically opened. A convenient green button positioned at the bottom right corner of the page will appear, prompting you to click and select your desired host from a user-friendly drop-down menu. Enjoy seamless video streaming with the host of your choice!
当前为
// ==UserScript== // @name Host Selector // @version 3 // @description:de Ermöglicht Auswahl von Video-Host und speichert die Auswahl. Funktioniert bei https://aniworld.to/ und https://s.to // @description:en Enables selection of video host and saves the choice. Works on https://aniworld.to/ and https://s.to // @description:ja ビデオホストの選択と選択内容の保存を可能にします。https://aniworld.to/ および https://s.to で動作します。 // @author 𝕭𝖚𝖉𝖚𝖒𝖟 // @icon https://w0.peakpx.com/wallpaper/40/813/HD-wallpaper-walpaper-zedge.jpg // @match https://aniworld.to/* // @match https://s.to/serie/stream/* // @grant GM_addStyle // @namespace http://tampermonkey.net/ // @description Enhanced GUI for aniworld.to and s.to websites, allowing you to effortlessly choose your preferred video host and have it automatically opened. A convenient green button positioned at the bottom right corner of the page will appear, prompting you to click and select your desired host from a user-friendly drop-down menu. Enjoy seamless video streaming with the host of your choice! // ==/UserScript== (function () { 'use strict'; console.log('[Host Selector] Skript startet...'); // --- Prüfen, ob GM_* Funktionen verfügbar sind --- if (typeof GM_getValue === 'undefined' || typeof GM_setValue === 'undefined' || typeof GM_addStyle === 'undefined') { console.error('[Host Selector] Fehler: GM_getValue, GM_setValue oder GM_addStyle nicht verfügbar! Stellen Sie sicher, dass Tampermonkey/Greasemonkey korrekt läuft und die @grant-Anweisungen vorhanden sind.'); alert('[Host Selector] Fehler: Benötigte GM_* Funktionen nicht gefunden. Skript kann nicht korrekt ausgeführt werden.'); return; // Skript beenden, wenn wichtige Funktionen fehlen } else { console.log('[Host Selector] GM_* Funktionen verfügbar.'); } // --- Konfiguration --- const hosterListSelector = 'ul.row > li'; // Selektor für die Listenelemente der Hoster const hosterLinkSelector = 'a.watchEpisode'; // Selektor für die Links zu den einzelnen Hostern (innerhalb li) const hosterNameSelector = 'h4'; // Selektor für den Namen des Hosters innerhalb des Links const hosterButtonSelector = '.hosterSiteVideoButton'; // Selektor für den eigentlichen Klick-Button im Link const clickDelay = 250; // Etwas längere Verzögerung vor dem Klick (in Millisekunden) const localStorageKey = 'preferredHoster'; // Schlüssel für GM Speicher const OBSERVER_TIMEOUT_MS = 15000; // Max. Wartezeit für Auto-Klick (15 Sekunden) // --- Funktion zum Klicken des bevorzugten Hoster-Links --- // Gibt true zurück, wenn der Klick-Versuch gestartet wurde, sonst false. function clickHosterLink(preferredHoster) { const hosterListItems = document.querySelectorAll(hosterListSelector); console.log(`[Host Selector] clickHosterLink: Aufgerufen mit preferredHoster="${preferredHoster}". Fand ${hosterListItems.length} Listenelemente.`); let foundAndClicked = false; // Wird true, wenn der Klick-Versuch startet for (const item of hosterListItems) { // Prüfen, ob das Element sichtbar ist if (window.getComputedStyle(item).display === 'none') { // console.log('[Host Selector] clickHosterLink: Überspringe unsichtbares Listenelement.'); // Optional: Weniger Logs continue; } const link = item.querySelector(hosterLinkSelector); if (!link) continue; const hosterNameElement = link.querySelector(hosterNameSelector); const button = link.querySelector(hosterButtonSelector); if (hosterNameElement) { const currentHosterName = hosterNameElement.innerText.trim(); // console.log(`[Host Selector] Prüfe sichtbaren Hoster: "${currentHosterName}"`); // Optional: Weniger Logs if (currentHosterName === preferredHoster) { console.log(`[Host Selector] Match gefunden für "${preferredHoster}"!`); if (button) { console.log(`[Host Selector] Button gefunden. Versuche Klick nach ${clickDelay}ms...`); // Klick wird verzögert ausgeführt setTimeout(() => { try { button.click(); console.log(`[Host Selector] Klick erfolgreich ausgelöst für "${preferredHoster}".`); } catch (e) { console.error(`[Host Selector] Fehler während button.click():`, e); } }, clickDelay); foundAndClicked = true; // WICHTIG: Setze auf true, da der Klick *versucht* wird break; // Schleife verlassen, Hoster gefunden und Klick initiiert } else { console.warn(`[Host Selector] Hoster "${preferredHoster}" gematcht, aber Button mit Selektor "${hosterButtonSelector}" nicht im Link gefunden.`); } } } else { // console.warn(`[Host Selector] Sichtbarer Link gefunden, aber Hoster-Namenselement mit Selektor "${hosterNameSelector}" nicht darin gefunden.`); // Optional: Weniger Logs } } // Gib zurück, ob der Klick-Versuch für den bevorzugten Hoster gestartet wurde if (!foundAndClicked && hosterListItems.length > 0) { console.log(`[Host Selector] clickHosterLink: Bevorzugter Hoster "${preferredHoster}" wurde unter den ${hosterListItems.length} sichtbaren Hostern nicht gefunden.`); } else if (hosterListItems.length === 0) { console.log(`[Host Selector] clickHosterLink: Keine Hoster-Listenelemente gefunden.`); } return foundAndClicked; // Gib den Status zurück } // --- Funktion zur Behandlung des automatischen Klickens beim Laden der Seite --- function autoClickPreferredHoster() { console.log('[Host Selector] Lese Hoster aus Speicher...'); const storedPreferredHoster = GM_getValue(localStorageKey, null); console.log(`[Host Selector] Wert gelesen für Schlüssel "${localStorageKey}":`, storedPreferredHoster); if (!storedPreferredHoster) { console.log('[Host Selector] Kein bevorzugter Hoster im Speicher gefunden. Automatisches Klicken übersprungen.'); return; } console.log(`[Host Selector] Bevorzugter Hoster gefunden: "${storedPreferredHoster}". Warte auf Hoster-Links...`); // --- Variablen für den Observer und Timeout --- let observer = null; let observerTimeout = null; // Funktion, die prüft und klickt. Gibt true zurück, wenn Klick ausgelöst wurde. const checkForLinksAndClick = () => { console.log(`[Host Selector] checkForLinksAndClick: Suche nach "${storedPreferredHoster}".`); const hosterItemsExist = document.querySelector(hosterListSelector); if (hosterItemsExist) { console.log(`[Host Selector] Mindestens ein Listenelement gefunden. Rufe clickHosterLink auf.`); // clickHosterLink gibt true zurück, wenn der Klick-Versuch gestartet wurde return clickHosterLink(storedPreferredHoster); } console.log(`[Host Selector] Noch keine Listenelemente gefunden.`); return false; // Hoster-Liste noch nicht gefunden }; // Funktion zum Stoppen des Observers und des Timeouts const stopObserver = (reason) => { if (observer) { observer.disconnect(); observer = null; console.log(`[Host Selector] MutationObserver gestoppt (${reason}).`); } if (observerTimeout) { clearTimeout(observerTimeout); observerTimeout = null; console.log(`[Host Selector] Observer-Timeout gelöscht (${reason}).`); } }; // 1. Zuerst prüfen, ob die Links vielleicht schon da sind if (checkForLinksAndClick()) { console.log('[Host Selector] Klick bei initialer Prüfung erfolgreich.'); return; // Kein Observer nötig } // 2. Wenn nicht, MutationObserver verwenden console.log('[Host Selector] Starte MutationObserver, um auf Listenelemente zu warten...'); observer = new MutationObserver((mutationsList, obs) => { console.log('[Host Selector] MutationObserver ausgelöst.'); // Prüfen, ob der bevorzugte Hoster jetzt geklickt werden kann if (checkForLinksAndClick()) { console.log('[Host Selector] Klick nach DOM-Änderung erfolgreich.'); stopObserver("Hoster gefunden und geklickt"); } else { // Noch nicht erfolgreich, warte auf weitere Mutationen oder Timeout console.log(`[Host Selector] Bevorzugter Hoster "${storedPreferredHoster}" nach Mutation noch nicht klickbar/gefunden.`); } }); // Beobachte Änderungen im Body observer.observe(document.body, { childList: true, // Achte auf hinzugefügte/entfernte Kind-Elemente subtree: true // Beobachte auch alle Unterelemente }); // 3. Setze ein Timeout, um den Observer zu stoppen, falls der Hoster nie erscheint console.log(`[Host Selector] Setze Observer-Timeout auf ${OBSERVER_TIMEOUT_MS / 1000} Sekunden.`); observerTimeout = setTimeout(() => { console.warn(`[Host Selector] Observer-Timeout erreicht. Bevorzugter Hoster "${storedPreferredHoster}" wurde nicht gefunden oder konnte nicht geklickt werden.`); stopObserver("Timeout"); }, OBSERVER_TIMEOUT_MS); } // --- Funktion zum Erstellen und Anzeigen des GUI-Popups --- function createGUI() { console.log('[Host Selector] createGUI aufgerufen.'); const existingPopup = document.getElementById('hostSelectorPopup'); if (existingPopup) { document.body.removeChild(existingPopup); } // --- Verfügbare Hoster dynamisch ermitteln --- const hosterListItems = document.querySelectorAll(hosterListSelector); const availableHostersSet = new Set(); console.log(`[Host Selector] GUI: Fand ${hosterListItems.length} potenzielle Hoster-Listenelemente.`); hosterListItems.forEach(item => { if (window.getComputedStyle(item).display !== 'none') { const hosterNameElement = item.querySelector(hosterNameSelector); if (hosterNameElement) { const hosterName = hosterNameElement.innerText.trim(); if (hosterName) { availableHostersSet.add(hosterName); console.log(`[Host Selector] GUI: Füge sichtbaren Hoster "${hosterName}" zur Liste hinzu.`); } } } else { // console.log('[Host Selector] GUI: Überspringe unsichtbares Hoster-Listenelement.'); } }); const availableHosters = Array.from(availableHostersSet).sort(); console.log('[Host Selector] GUI: Verfügbare Hoster ermittelt:', availableHosters); let optionsHTML = ''; if (availableHosters.length > 0) { optionsHTML = availableHosters.map(hoster => `<option value="${hoster}">${hoster}</option>` ).join(''); } else { optionsHTML = '<option value="">Keine Hoster gefunden</option>'; console.warn('[Host Selector] GUI: Keine sichtbaren Hoster gefunden, um die Dropdown-Liste zu füllen.'); } // --- Ende Hoster ermitteln --- const popupDiv = document.createElement('div'); popupDiv.id = 'hostSelectorPopup'; // Style für das Popup popupDiv.style.position = 'fixed'; popupDiv.style.top = '50%'; popupDiv.style.left = '50%'; popupDiv.style.transform = 'translate(-50%, -50%)'; popupDiv.style.background = '#ffffff'; popupDiv.style.border = '1px solid #ddd'; popupDiv.style.boxShadow = '0px 0px 15px rgba(0, 0, 0, 0.2)'; popupDiv.style.maxWidth = '400px'; popupDiv.style.width = '90%'; popupDiv.style.padding = '25px'; popupDiv.style.borderRadius = '8px'; popupDiv.style.fontFamily = 'Arial, sans-serif'; popupDiv.style.zIndex = '10000'; popupDiv.style.boxSizing = 'border-box'; // HTML-Inhalt des Popups popupDiv.innerHTML = ` <h2 style="font-size: 20px; margin-top:0; margin-bottom: 20px; color: #333; text-align: center;">Bevorzugter Hoster</h2> <label for="preferredHosterSelect" style="display: block; font-size: 16px; color: #555; margin-bottom: 8px;">Verfügbarer Hoster:</label> <select id="preferredHosterSelect" style="width: 100%; padding: 12px; margin-bottom: 25px; font-size: 16px; border: 1px solid #ccc; border-radius: 4px; color: #555; box-sizing: border-box;"> ${optionsHTML} </select> <div style="display: flex; justify-content: space-between; gap: 10px;"> <button id="submitButton" style="flex-grow: 1; background-color: #4CAF50; color: white; padding: 12px 20px; border: none; border-radius: 4px; cursor: pointer; font-size: 16px;">Auswählen & Speichern</button> <button id="closeButton" style="background-color: #f44336; color: white; padding: 12px 20px; border: none; border-radius: 4px; cursor: pointer; font-size: 16px;">Schließen</button> </div> `; document.body.appendChild(popupDiv); // Gespeicherten Hoster im Dropdown vorauswählen const storedPreferredHoster = GM_getValue(localStorageKey, null); const preferredHosterSelect = document.getElementById('preferredHosterSelect'); console.log(`[Host Selector] GUI: Lade gespeicherten Wert "${storedPreferredHoster}" in Select-Box.`); if (preferredHosterSelect && storedPreferredHoster) { if (Array.from(preferredHosterSelect.options).some(option => option.value === storedPreferredHoster)) { preferredHosterSelect.value = storedPreferredHoster; console.log(`[Host Selector] GUI: Gespeicherter Hoster "${storedPreferredHoster}" ist verfügbar und wurde ausgewählt.`); } else { console.log(`[Host Selector] GUI: Gespeicherter Hoster "${storedPreferredHoster}" ist aktuell nicht verfügbar.`); } } else if (preferredHosterSelect && preferredHosterSelect.options.length > 0 && preferredHosterSelect.options[0].value !== "") { console.log('[Host Selector] GUI: Kein Hoster gespeichert. Erster verfügbarer Hoster:', preferredHosterSelect.options[0]?.value); } // Event Listener für Buttons const submitButton = document.getElementById('submitButton'); submitButton.addEventListener('click', () => { if (preferredHosterSelect.value && preferredHosterSelect.value !== "") { const selectedHoster = preferredHosterSelect.value; console.log(`[Host Selector] GUI: "Auswählen" geklickt. Speichere "${selectedHoster}"...`); GM_setValue(localStorageKey, selectedHoster); console.log(`[Host Selector] GUI: Wert für Schlüssel "${localStorageKey}" gespeichert.`); console.log('[Host Selector] GUI: Versuche sofortigen Klick nach Auswahl...'); clickHosterLink(selectedHoster); // Versuche sofort zu klicken document.body.removeChild(popupDiv); console.log('[Host Selector] GUI: Popup geschlossen.'); } else { console.warn('[Host Selector] GUI: Kein gültiger Hoster zum Speichern ausgewählt.'); alert("Bitte wähle einen verfügbaren Hoster aus."); } }); const closeButton = document.getElementById('closeButton'); closeButton.addEventListener('click', () => { console.log('[Host Selector] GUI: "Schließen" geklickt.'); document.body.removeChild(popupDiv); }); } // --- Funktion zum Hinzufügen des GUI-Buttons zur Seite --- function addGUIButton() { console.log('[Host Selector] Füge GUI-Button hinzu...'); const existingButton = document.getElementById('hostSelectorButton'); if (existingButton) { // Optional: Entfernen, falls alter Button Probleme macht // document.body.removeChild(existingButton); console.log('[Host Selector] GUI-Button existiert bereits.'); return; // Nicht erneut hinzufügen } const button = document.createElement('button'); button.id = 'hostSelectorButton'; button.innerText = '⚙️ Hoster'; button.style.position = 'fixed'; button.style.bottom = '15px'; button.style.right = '15px'; button.style.backgroundColor = '#673AB7'; button.style.color = 'white'; button.style.padding = '8px 12px'; button.style.border = 'none'; button.style.borderRadius = '5px'; button.style.cursor = 'pointer'; button.style.fontSize = '14px'; button.style.zIndex = '9999'; button.style.boxShadow = '0 2px 5px rgba(0,0,0,0.2)'; button.title = 'Bevorzugten Hoster auswählen'; button.addEventListener('click', createGUI); document.body.appendChild(button); console.log('[Host Selector] GUI-Button hinzugefügt.'); } // --- Hauptausführung --- console.log('[Host Selector] Starte Hauptausführung...'); // Füge den Button hinzu (oder stelle sicher, dass er da ist) // Die Prüfung auf Existenz erfolgt jetzt in addGUIButton selbst. addGUIButton(); // Starte den Versuch, automatisch zu klicken autoClickPreferredHoster(); console.log('[Host Selector] Hauptausführung initial abgeschlossen (Observer läuft ggf. weiter).'); })(); // Ende der IIFE