// ==UserScript== // @name Avistaz+ // @version 1.0 // @description Enhancements for Avistaz // @author Mio. // @namespace https://github.com/dear-clouds/mio-userscripts // @supportURL https://github.com/dear-clouds/mio-userscripts/issues // @icon https://www.google.com/s2/favicons?sz=64&domain=avistaz.to // @license GPL-3.0 // @match *://*.avistaz.to/* // @require https://cdnjs.cloudflare.com/ajax/libs/jszip/3.7.1/jszip.min.js // @require https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js // @grant none // @downloadURL https://update.greasyfork.icu/scripts/518249/Avistaz%2B.user.js // @updateURL https://update.greasyfork.icu/scripts/518249/Avistaz%2B.meta.js // ==/UserScript== (function() { 'use strict'; const username = document.querySelector("a[href*='/profile/']").getAttribute('href').split('/').pop(); const STORAGE_KEY_FULL_SCAN_COMPLETED = `avistaz+_${username}_full_scan_completed`; let stopFetching = false; // Function to simulate a click on the "Thank Uploader" button function clickThankButton(torrentId) { const thankButton = document.querySelector(`button#btn-torrent-thank[data-id='${torrentId}']`); if (thankButton) { thankButton.click(); console.log("Thanked uploader for torrent ID: " + torrentId); } } // Function to delete full scan completed state from localStorage function resetFullScanState() { localStorage.removeItem(STORAGE_KEY_FULL_SCAN_COMPLETED); console.log("Full scan state has been reset. You can now retry a full scan."); } // Add a click event listener to each download link document.querySelectorAll("a.btn.btn-xs.btn-primary").forEach(downloadLink => { downloadLink.addEventListener("click", function(event) { const torrentIdMatch = this.href.match(/\/download\/torrent\/(\d+)/); if (torrentIdMatch && torrentIdMatch[1]) { const torrentId = torrentIdMatch[1]; // Set a small timeout to ensure the "Thank Uploader" button is available setTimeout(() => { clickThankButton(torrentId); }, 500); } }); }); // Function to bypass anon.to redirects function bypassAnonRedirects() { const allLinks = document.querySelectorAll('a'); allLinks.forEach(link => { if (link.href.startsWith('https://anon.to/?')) { const realURL = link.href.split('?')[1]; if (realURL) { link.href = decodeURIComponent(realURL); if (window.location.href.startsWith('https://anon.to/')) { window.location.href = decodeURIComponent(realURL); } } } }); } bypassAnonRedirects(); // Function to gather all Hit & Run entries from history pages async function collectHitAndRuns() { let currentPage = 1; const collectedHitAndRuns = []; let isFullScan = false; const fullScanCompleted = localStorage.getItem(STORAGE_KEY_FULL_SCAN_COMPLETED) === 'true'; let totalPages = null; const noHnrMessage = document.querySelector('.table-responsive h3'); if (noHnrMessage) { noHnrMessage.innerHTML = '
'; } else { console.log("No 'No Hit & Run Torrents' message found, skipping Hit & Run collection."); return; } function updateProgress(current, total) { const loadingIcon = document.querySelector('.loading-icon'); if (loadingIcon) { loadingIcon.innerHTML = ` Searching for Hit & Run torrents... (${current}/${total})`; } } async function fetchPage(pageNumber) { if (stopFetching) { console.log(`Skipping page ${pageNumber} as stop condition was met.`); return; } console.log(`Fetching page ${pageNumber}`); try { const response = await fetch(`https://avistaz.to/profile/${username}/history?page=${pageNumber}`); const html = await response.text(); const parser = new DOMParser(); const doc = parser.parseFromString(html, 'text/html'); const hitAndRunRows = doc.querySelectorAll('tr'); // Get total number of pages from pagination element if (totalPages === null) { const pagination = doc.querySelector('ul.pagination'); if (pagination) { const pageNumbers = Array.from(pagination.querySelectorAll('a[href*="?page="]')) .map(link => parseInt(link.textContent.trim(), 10)) .filter(page => !isNaN(page)); if (pageNumbers.length > 0) { totalPages = Math.max(...pageNumbers); console.log(`Total pages detected: ${totalPages}`); } } if (!totalPages) { totalPages = 1; // Fallback if pagination is missing } } for (const row of hitAndRunRows) { if (stopFetching) { console.log(`Stopping processing of rows on page ${pageNumber} because stop condition was met.`); return; } // Specifically select the "Added" column to find the date const addedDateCell = row.querySelectorAll('td')[8]; if (addedDateCell) { const addedDateElement = addedDateCell.querySelector('span[data-toggle="tooltip"]'); if (addedDateElement) { const addedDateText = addedDateElement.textContent.trim().toLowerCase(); const originalTitleText = addedDateElement.getAttribute('data-original-title')?.toLowerCase().trim() || ""; // console.log(`Checking date text: "${addedDateText}" and data-original-title: "${originalTitleText}" on page: ${pageNumber}`); // Check if either the text content or the attribute contains "1 month" if (fullScanCompleted && (addedDateText.includes("1 month") || originalTitleText.includes("1 month"))) { stopFetching = true; console.log(`Stopping fetch, found torrent added over a month ago on page: ${pageNumber}`); removeLoadingIcon(); break; } } } if (row.classList.contains('danger')) { collectedHitAndRuns.push(row.outerHTML); updateHitAndRunTable(row); } } if (!fullScanCompleted) { isFullScan = true; // Indicate this is a full scan } updateProgress(pageNumber, totalPages); currentPage++; } catch (err) { console.error(`Error fetching history page ${pageNumber}: `, err); } } // Fetch pages in parallel but with proper stopping control async function fetchNextPages(startPage, pagesToFetch = 5) { if (stopFetching) { removeLoadingIcon(); return; } const fetchPromises = []; for (let i = 0; i < pagesToFetch; i++) { if (startPage + i <= (totalPages ?? 1) && !stopFetching) { fetchPromises.push(fetchPage(startPage + i)); } } await Promise.all(fetchPromises); if (!stopFetching && currentPage <= totalPages) { console.log(`Finished batch, continuing from page ${currentPage}`); await fetchNextPages(currentPage, pagesToFetch); } else { if (isFullScan && !stopFetching) { console.log("Reached the last page, updating cache as full scan completed."); localStorage.setItem(STORAGE_KEY_FULL_SCAN_COMPLETED, 'true'); } removeLoadingIcon(); } } console.log(`Starting Hit & Run collection from page ${currentPage}`); await fetchNextPages(currentPage, 5); } // Function to update Hit & Run entries as they are found function updateHitAndRunTable(hitAndRunRow) { const tableContainer = document.querySelector('.table-responsive'); if (tableContainer) { // Check if we need to replace the "No Hit & Run Torrents" message const noHnrMessage = tableContainer.querySelector('h3'); if (noHnrMessage) { noHnrMessage.remove(); } // If the table doesn't already exist, create it let table = tableContainer.querySelector('table'); if (!table) { let tableHtml = '| Type | Torrent | Download | Seeding | Completed | Uploaded | Downloaded | Ratio | Added | Updated | Seed Time | Hit & Run |
|---|