// ==UserScript== // @name DropGalaxy Auto Skip // @namespace http://tampermonkey.net/ // @version 1.7.2 // @description Auto skip ads and auto download on DropGalaxy // @author kleptomaniac14 // @match https://dropgalaxy.com/* // @match https://dropgalaxy.co/* // @match https://financemonk.net/* // @icon https://www.google.com/s2/favicons?domain=dropgalaxy.com // @grant GM.getValue // @grant GM.setValue // @grant GM.deleteValue // @license GNU GPLv2 // @downloadURL https://update.greasyfork.icu/scripts/492017/DropGalaxy%20Auto%20Skip.user.js // @updateURL https://update.greasyfork.icu/scripts/492017/DropGalaxy%20Auto%20Skip.meta.js // ==/UserScript== // Setting esversion to 11 to use optional chaining. /* jshint esversion: 11 */ (function () { "use strict"; // Constants const MAX_IDENTIFICATION_RETRIES = 3; const STORAGE_SCRIPT_KEY = "dg_auto_skip_config"; const STORAGE_CACHE_KEY = "dg_auto_skip_cache"; const DG_AUTO_SKIP_CONFIG = { fallbackDlProvider: "vikingfile", // 'vikingfile, 'gofile // Provider to use in case DDL is not available. cacheDlLinks: false, cacheExpiry: "1week", // '1hour', '1day', '1week', '1month', 'forever' alertCaptchaAvailable: false, // Alert when CAPTCHA is available }; // Global Variables let intervalId = null; let identificationRetries = 0; let config = {}; let cache = {}; let currentPageLinks = null; // Store current page links for toggle button let shouldStopScript = false; // Utils const log = (message, ...rest) => console.log( `[DropGalaxy Auto Skip] [ID: ${intervalId}] ${message}`, ...rest ); const getFileMetadata = () => { const filename = document.getElementsByTagName("h1")?.[0]?.innerText; const fileSize = document.getElementsByClassName("fa-hdd")?.[0]?.parentElement ?.children?.[1]?.innerText; const reportAbuseHref = document.getElementsByClassName("fa-flag")?.[0]?.parentElement ?.children?.[1]?.href; let fileId = null; if (reportAbuseHref) { const url = new URL(reportAbuseHref); fileId = url.searchParams.get("id"); } return { filename, fileSize, fileId }; }; const validateCache = () => { const now = Date.now(); const eightHours = 8 * 60 * 60 * 1000; Object.keys(cache).forEach((fileId) => { const entry = cache[fileId]; if (entry?.expiry && entry.expiry < now) { delete cache[fileId]; } else if (entry?.createdAt && now - entry.createdAt > eightHours) { // Remove the DDL link after 8 hours, keep mirrors if any if (entry.urls) { entry.urls.ddl = ""; } } }); }; const loadConfig = async () => { const configString = await GM.getValue(STORAGE_SCRIPT_KEY); try { config = JSON.parse(configString); } catch (error) { log("Error parsing config, using default", error); config = DG_AUTO_SKIP_CONFIG; } if (!config || typeof config !== "object") { config = DG_AUTO_SKIP_CONFIG; } }; const loadCache = async () => { const cacheString = await GM.getValue(STORAGE_CACHE_KEY); try { cache = JSON.parse(cacheString); } catch (error) { log("Error parsing cache, starting fresh", error); cache = {}; } if (!cache || typeof cache !== "object") { cache = {}; } validateCache(); }; const saveCache = async ({ fileId, filename, fileSize, links }) => { if (!Array.isArray(links) || links.length === 0) return; // For each link, extract their domain, identify if it is DDL or alternative // and save to cache with expiry const now = Date.now(); const urls = { ddl: "", vikingfile: "", gofile: "", }; links.forEach((link) => { const url = new URL(link); const domain = url.hostname; if (domain.includes("a2zupload")) { urls.ddl = link; } else if (domain.includes("vikingfile")) { urls.vikingfile = link; } else if (domain.includes("gofile")) { urls.gofile = link; } }); const expiry = (() => { switch (config.cacheExpiry) { case "1hour": return now + 3600 * 1000; case "1day": return now + 24 * 3600 * 1000; case "1week": return now + 7 * 24 * 3600 * 1000; case "1month": return now + 30 * 24 * 3600 * 1000; case "forever": return null; } })(); cache[fileId] = { filename, fileSize, urls, expiry, createdAt: now }; validateCache(); await GM.setValue(STORAGE_CACHE_KEY, JSON.stringify(cache)); log("Cache saved"); }; const handleSaveConfig = async (newConfig) => { await GM.setValue(STORAGE_SCRIPT_KEY, JSON.stringify(newConfig)); config = newConfig; log("Settings saved"); }; const handleResetConfig = async () => { if (confirm("Reset settings?")) { await GM.deleteValue(STORAGE_SCRIPT_KEY); log("Settings reset"); } }; const checkCachedFile = () => { const { fileId } = getFileMetadata(); const hasValidURLs = Object.values(cache[fileId]?.urls ?? {}).some( (url) => url ); if (hasValidURLs) { shouldStopScript = true; showModalWithLinks(cache[fileId].urls); return true; } return false; }; const showModalWithLinks = async (urls) => { // Store links globally for toggle button currentPageLinks = urls; // Check if modal already exists, if so remove it (toggle behavior) const existingModal = document.getElementById("dg-links-modal"); if (existingModal) { existingModal.remove(); return; // Exit to toggle off } // Create modal const modal = document.createElement("div"); modal.id = "dg-links-modal"; modal.style.cssText = ` position: fixed; top: 70px; right: 20px; left: 20px; width: auto; max-width: 320px; background: var(--bg-color, #ffffff); border: 1px solid var(--border-color, #ddd); border-radius: 8px; box-shadow: 0 4px 12px rgba(0,0,0,0.3); z-index: 9999999999; padding: 0; color: var(--text-color, #000000); `; // Adjust for desktop (wider screens) if (window.innerWidth > 600) { modal.style.left = "auto"; modal.style.width = "320px"; } const modalContent = document.createElement("div"); modalContent.style.cssText = ` background: var(--bg-color, #ffffff); padding: 20px; border-radius: 8px; position: relative; color: var(--text-color, #000000); `; // Close button const closeBtn = document.createElement("button"); closeBtn.innerHTML = "×"; closeBtn.style.cssText = ` position: absolute; top: 5px; right: 10px; background: none; border: none; font-size: 18px; cursor: pointer; color: var(--text-muted, #999999); `; closeBtn.onclick = () => { modal.remove(); // Show links button again when modal is closed if (currentPageLinks) { window.toggleLinksButton(true); } }; // Title const title = document.createElement("h3"); title.textContent = "Available Download Links"; title.style.cssText = "margin: 0 0 15px 0; font-size: 16px; color: var(--text-color, #000000);"; // File info section const { fileId } = getFileMetadata(); const cachedFile = cache[fileId]; if (cachedFile && (cachedFile?.filename || cachedFile?.fileSize)) { const fileInfo = document.createElement("div"); fileInfo.style.cssText = "background: var(--input-bg, #f8f9fa); padding: 10px; border-radius: 5px; margin-bottom: 15px; border: 1px solid var(--border-color, #ddd);"; if (cachedFile?.filename) { const filename = document.createElement("div"); filename.textContent = `File: ${cachedFile.filename}`; filename.style.cssText = "font-weight: bold; color: var(--text-color, #000000); margin-bottom: 5px; word-break: break-word;"; fileInfo.appendChild(filename); } if (cachedFile?.fileSize) { const fileSize = document.createElement("div"); fileSize.textContent = `Size: ${cachedFile.fileSize}`; fileSize.style.cssText = "color: var(--text-muted, #666666); font-size: 12px;"; fileInfo.appendChild(fileSize); } modalContent.appendChild(fileInfo); } // Links list const linksList = document.createElement("div"); linksList.style.cssText = "display: flex; flex-direction: column; gap: 10px; margin-bottom: 10px;"; // Add links if (urls.ddl) { const a = document.createElement("a"); a.href = urls.ddl; a.textContent = "Direct Download Link"; a.target = "_blank"; a.style.cssText = "background: #22a76d; color: white; padding: 10px; border-radius: 5px; text-align: center; text-decoration: none; font-weight: bold;"; linksList.appendChild(a); } if (urls.vikingfile) { const a = document.createElement("a"); a.href = urls.vikingfile; a.textContent = "VikingFile Mirror"; a.target = "_blank"; a.style.cssText = "background: #007bff; color: white; padding: 10px; border-radius: 5px; text-align: center; text-decoration: none; font-weight: bold;"; linksList.appendChild(a); } if (urls.gofile) { const a = document.createElement("a"); a.href = urls.gofile; a.textContent = "GoFile Mirror"; a.target = "_blank"; a.style.cssText = "background: #6c757d; color: white; padding: 10px; border-radius: 5px; text-align: center; text-decoration: none; font-weight: bold;"; linksList.appendChild(a); } // Show message if no links are available if (!urls.ddl && !urls.vikingfile && !urls.gofile) { const noLinks = document.createElement("div"); noLinks.textContent = "No links available."; noLinks.style.cssText = "color: var(--text-muted, #999999); text-align: center; padding: 10px;"; linksList.appendChild(noLinks); } // Remove From Cache button click handler const handleRemoveFromCache = async (e) => { e.stopPropagation(); const { fileId } = getFileMetadata(); if (!fileId) return; if (cache && cache[fileId]) { delete cache[fileId]; try { await GM.setValue(STORAGE_CACHE_KEY, JSON.stringify(cache)); log(`Removed ${fileId} from cache`); } catch (err) { log("Error saving cache after removal", err); } } // Close modal and restart page watcher modal.remove(); shouldStopScript = false; if (typeof startPageWatcher === "function") startPageWatcher(); }; // Remove From Cache button const removeBtn = document.createElement("button"); removeBtn.innerText = "Remove From Cache"; removeBtn.style.cssText = ` background: #dc3545; color: white; padding: 8px; border-radius: 5px; text-align: center; border: none; cursor: pointer; font-weight: bold; width: 100%; margin-top: 8px; `; removeBtn.onclick = handleRemoveFromCache; // Assemble modal modalContent.appendChild(closeBtn); modalContent.appendChild(title); modalContent.appendChild(linksList); modalContent.appendChild(removeBtn); modal.appendChild(modalContent); document.body.appendChild(modal); // Close on outside click setTimeout(() => { document.addEventListener("click", function clickHandler(e) { if (!modal.contains(e.target)) { modal.remove(); document.removeEventListener("click", clickHandler); } }); }, 100); }; const showCacheBrowser = async () => { // Check if modal already exists, if so remove it (toggle behavior) const existingModal = document.getElementById("dg-cache-browser-modal"); if (existingModal) { existingModal.remove(); return; } // Create modal const modal = document.createElement("div"); modal.id = "dg-cache-browser-modal"; modal.style.cssText = ` position: fixed; top: 70px; right: 20px; left: 20px; width: auto; max-width: 500px; max-height: 70vh; background: var(--bg-color, #ffffff); border: 1px solid var(--border-color, #ddd); border-radius: 8px; box-shadow: 0 4px 12px rgba(0,0,0,0.3); z-index: 9999999999; padding: 0; color: var(--text-color, #000000); display: flex; flex-direction: column; `; // Adjust for desktop (wider screens) if (window.innerWidth > 600) { modal.style.left = "auto"; modal.style.width = "500px"; } const modalContent = document.createElement("div"); modalContent.style.cssText = ` background: var(--bg-color, #ffffff); padding: 20px; border-radius: 8px; position: relative; color: var(--text-color, #000000); display: flex; flex-direction: column; max-height: 70vh; `; // Close button const closeBtn = document.createElement("button"); closeBtn.innerHTML = "×"; closeBtn.style.cssText = ` position: absolute; top: 5px; right: 10px; background: none; border: none; font-size: 18px; cursor: pointer; color: var(--text-muted, #999999); `; closeBtn.onclick = () => modal.remove(); // Title const title = document.createElement("h3"); title.textContent = "Cached Files"; title.style.cssText = "margin: 0 0 15px 0; font-size: 16px; color: var(--text-color, #000000);"; // Search box const searchBox = document.createElement("input"); searchBox.type = "text"; searchBox.placeholder = "Search files..."; searchBox.style.cssText = ` width: 100%; padding: 8px; margin-bottom: 15px; border: 1px solid var(--border-color, #ddd); border-radius: 4px; background: var(--input-bg, #ffffff); color: var(--text-color, #000000); font-size: 12px; `; // Files container const filesContainer = document.createElement("div"); filesContainer.style.cssText = ` flex: 1; overflow-y: auto; display: flex; flex-direction: column; gap: 10px; `; // Function to render files const renderFiles = (searchTerm = "") => { filesContainer.innerHTML = ""; const cacheEntries = Object.entries(cache); if (cacheEntries.length === 0) { const emptyMsg = document.createElement("div"); emptyMsg.textContent = "No cached files."; emptyMsg.style.cssText = "text-align: center; color: var(--text-muted, #999999); padding: 20px;"; filesContainer.appendChild(emptyMsg); return; } const filteredEntries = cacheEntries.filter(([fileId, data]) => { if (!searchTerm) return true; const term = searchTerm.toLowerCase(); return ( data.filename?.toLowerCase().includes(term) || data.fileSize?.toLowerCase().includes(term) || fileId.toLowerCase().includes(term) ); }); if (filteredEntries.length === 0) { const noResults = document.createElement("div"); noResults.textContent = "No files match your search."; noResults.style.cssText = "text-align: center; color: var(--text-muted, #999999); padding: 20px;"; filesContainer.appendChild(noResults); return; } filteredEntries.forEach(([fileId, data]) => { const fileCard = document.createElement("div"); fileCard.style.cssText = ` background: var(--input-bg, #f8f9fa); padding: 12px; border-radius: 5px; border: 1px solid var(--border-color, #ddd); cursor: pointer; transition: background 0.2s; `; fileCard.onmouseenter = () => (fileCard.style.background = "var(--border-color, #e9ecef)"); fileCard.onmouseleave = () => (fileCard.style.background = "var(--input-bg, #f8f9fa)"); // Filename const filename = document.createElement("div"); filename.textContent = data.filename || "Unknown File"; filename.style.cssText = "font-weight: bold; color: var(--text-color, #000000); margin-bottom: 5px; word-break: break-word; font-size: 13px;"; // File size const fileSize = document.createElement("div"); fileSize.textContent = `Size: ${data.fileSize || "Unknown"}`; fileSize.style.cssText = "color: var(--text-muted, #666666); font-size: 11px; margin-bottom: 8px;"; // Links row const linksRow = document.createElement("div"); linksRow.style.cssText = "display: flex; gap: 5px; flex-wrap: wrap; margin-bottom: 8px;"; // Add link buttons if (data.urls?.ddl) { const ddlBtn = document.createElement("a"); ddlBtn.href = data.urls.ddl; ddlBtn.textContent = "DDL"; ddlBtn.target = "_blank"; ddlBtn.style.cssText = "background: #22a76d; color: white; padding: 4px 8px; border-radius: 3px; text-decoration: none; font-size: 10px; font-weight: bold;"; linksRow.appendChild(ddlBtn); } if (data.urls?.vikingfile) { const vikingBtn = document.createElement("a"); vikingBtn.href = data.urls.vikingfile; vikingBtn.textContent = "Viking"; vikingBtn.target = "_blank"; vikingBtn.style.cssText = "background: #007bff; color: white; padding: 4px 8px; border-radius: 3px; text-decoration: none; font-size: 10px; font-weight: bold;"; linksRow.appendChild(vikingBtn); } if (data.urls?.gofile) { const gofileBtn = document.createElement("a"); gofileBtn.href = data.urls.gofile; gofileBtn.textContent = "GoFile"; gofileBtn.target = "_blank"; gofileBtn.style.cssText = "background: #6c757d; color: white; padding: 4px 8px; border-radius: 3px; text-decoration: none; font-size: 10px; font-weight: bold;"; linksRow.appendChild(gofileBtn); } // Delete button const deleteBtn = document.createElement("button"); deleteBtn.textContent = "Delete"; deleteBtn.style.cssText = "background: #dc3545; color: white; padding: 4px 8px; border-radius: 3px; border: none; cursor: pointer; font-size: 10px; font-weight: bold;"; deleteBtn.onclick = async (e) => { e.stopPropagation(); if (confirm(`Delete cached file: ${data.filename}?`)) { delete cache[fileId]; await GM.setValue(STORAGE_CACHE_KEY, JSON.stringify(cache)); log(`Deleted ${fileId} from cache`); renderFiles(searchBox.value); } }; linksRow.appendChild(deleteBtn); fileCard.appendChild(filename); fileCard.appendChild(fileSize); fileCard.appendChild(linksRow); filesContainer.appendChild(fileCard); }); }; // Search box event searchBox.oninput = () => renderFiles(searchBox.value); // Clear All button const clearAllBtn = document.createElement("button"); clearAllBtn.textContent = "Clear All Cache"; clearAllBtn.style.cssText = ` background: #dc3545; color: white; padding: 8px; border-radius: 5px; text-align: center; border: none; cursor: pointer; font-weight: bold; width: 100%; margin-top: 10px; font-size: 12px; `; clearAllBtn.onclick = async () => { if (confirm("Are you sure you want to clear all cached files?")) { cache = {}; await GM.setValue(STORAGE_CACHE_KEY, JSON.stringify(cache)); log("Cache cleared"); renderFiles(); } }; // Assemble modal modalContent.appendChild(closeBtn); modalContent.appendChild(title); modalContent.appendChild(searchBox); modalContent.appendChild(filesContainer); modalContent.appendChild(clearAllBtn); modal.appendChild(modalContent); document.body.appendChild(modal); // Initial render renderFiles(); // Close on outside click setTimeout(() => { document.addEventListener("click", function clickHandler(e) { if (!modal.contains(e.target) && e.target.id !== "cache-browser-btn") { modal.remove(); document.removeEventListener("click", clickHandler); } }); }, 100); }; const showSettingsUI = () => { // Create floating settings button const settingsBtn = document.createElement("button"); settingsBtn.innerHTML = "⚙️"; settingsBtn.title = "Settings"; settingsBtn.style.cssText = ` position: fixed; top: 20px; right: 20px; width: 40px; height: 40px; border-radius: 50%; background: #22a76d; border: none; color: white; cursor: pointer; z-index: 9999999999; font-size: 16px; `; // Create floating links button const linksBtn = document.createElement("button"); linksBtn.innerHTML = "🔗"; linksBtn.title = "Download Links"; linksBtn.style.cssText = ` position: fixed; top: 20px; right: 120px; width: 40px; height: 40px; border-radius: 50%; background: #007bff; border: none; color: white; cursor: pointer; z-index: 9999999999; font-size: 16px; display: none; `; // Links button click handler linksBtn.onclick = () => { if (currentPageLinks) { showModalWithLinks(currentPageLinks); } }; // Create floating cache browser button const cacheBtn = document.createElement("button"); cacheBtn.id = "cache-browser-btn"; cacheBtn.innerHTML = "📦"; cacheBtn.title = "Cache Browser"; cacheBtn.style.cssText = ` position: fixed; top: 20px; right: 70px; width: 40px; height: 40px; border-radius: 50%; background: #6c757d; border: none; color: white; cursor: pointer; z-index: 9999999999; font-size: 16px; `; // Cache button click handler cacheBtn.onclick = () => showCacheBrowser(); // Function to show/hide links button based on availability window.toggleLinksButton = (show = false) => { linksBtn.style.display = show ? "block" : "none"; }; // Create modal const modal = document.createElement("div"); modal.style.cssText = ` display: none; position: fixed; top: 70px; right: 20px; width: 280px; background: var(--bg-color, #ffffff); border: 1px solid var(--border-color, #ddd); border-radius: 8px; box-shadow: 0 4px 12px rgba(0,0,0,0.3); z-index: 9999999999; padding: 0; color: var(--text-color, #000000); `; const modalContent = document.createElement("div"); modalContent.style.cssText = ` background: var(--bg-color, #ffffff); padding: 20px; border-radius: 8px; position: relative; color: var(--text-color, #000000); `; modalContent.innerHTML = `