Skip to content

Instantly share code, notes, and snippets.

@motebaya
Last active April 24, 2026 12:27
Show Gist options
  • Select an option

  • Save motebaya/baf74af2cfd1391b7725be2de3958911 to your computer and use it in GitHub Desktop.

Select an option

Save motebaya/baf74af2cfd1391b7725be2de3958911 to your computer and use it in GitHub Desktop.
TamperMonkey: MediaFire Bulk Download with auto-download flow and aggressive popup prevention.
// ==UserScript==
// @name MediaFire Bulk download
// @namespace http://tampermonkey.net/
// @version 2.1
// @description Adds a DOWNLOAD ALL button on MediaFire folder pages and automatically triggers downloads on file pages while blocking popup/ads.
// @author @github.com/motebaya
// @license MIT
// @icon https://www.mediafire.com/favicon.ico
// @match https://www.mediafire.com/folder/*
// @match http://www.mediafire.com/folder/*
// @match https://www.mediafire.com/file*
// @match http://www.mediafire.com/file*
// @match https://www.mediafire.com/file_premium*
// @match http://www.mediafire.com/file_premium*
// @grant none
// @run-at document-start
// ==/UserScript==
(function () {
"use strict";
const href = location.href;
const isFolderPage = /:\/\/(?:www\.)?mediafire\.com\/folder\//i.test(href);
const isFilePage = /:\/\/(?:www\.)?mediafire\.com\/file(?:_premium)?/i.test(
href,
);
console.log("[MF] Script loaded:", href);
function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
/**
* Displays a flash notification message on the page.
* @param {string} [message="TEST"] - The message to display.
* @param {string} [type="success"] - The type of notification, either "success" or "error".
* @param {number} [duration=2200] - The duration in milliseconds for which the notification is shown.
*/
async function showFlash(
message = "TEST",
type = "success",
duration = 2200,
) {
let root = document.getElementById("mf-flash-root");
if (!root) {
root = document.createElement("div");
root.id = "mf-flash-root";
root.style.cssText = [
"position: fixed",
"top: 16px",
"left: 50%",
"transform: translateX(-50%)",
"z-index: 2147483647",
"pointer-events: none",
"display: flex",
"flex-direction: column",
"align-items: center",
].join(";");
document.documentElement.appendChild(root);
}
const notif = document.createElement("div");
notif.textContent = message;
const isError = type === "error";
notif.style.cssText = [
"margin-top: 10px",
"padding: 12px 18px",
"border-radius: 12px",
"color: #fff",
"font: 600 14px/1.4 Arial, sans-serif",
"box-shadow: 0 10px 30px rgba(0,0,0,.25)",
"opacity: 0",
"transform: translateY(-10px)",
"transition: opacity .25s ease, transform .25s ease",
"pointer-events: none",
"background: " + (isError ? "#d93025" : "#0050c9"),
"max-width: 90vw",
"white-space: nowrap",
].join(";");
root.appendChild(notif);
requestAnimationFrame(() => {
notif.style.opacity = "1";
notif.style.transform = "translateY(0)";
});
await sleep(duration - 300);
notif.style.opacity = "0";
notif.style.transform = "translateY(-10px)";
await sleep(duration);
notif.remove();
if (!root.children.length) root.remove();
}
/**
* file page handle - block popups/ads and auto click download button
*/
if (isFilePage) {
const originalOpen = window.open;
window.open = function (url, windowName, windowFeatures) {
showFlash("[POPUP BLOCKED] window.open: " + url, "success");
return {
closed: true,
close: function () {},
focus: function () {},
blur: function () {},
};
};
window.showModalDialog = function () {
showFlash("[POPUP BLOCKED] showModalDialog", "success");
return null;
};
window.showModelessDialog = function () {
showFlash("[POPUP BLOCKED] showModelessDialog", "success");
return null;
};
const originalAddEventListener = window.addEventListener;
window.addEventListener = function (type, listener, options) {
if (type === "beforeunload") {
showFlash("[POPUP BLOCKED] beforeunload handler blocked", "success");
return;
}
return originalAddEventListener.call(this, type, listener, options);
};
document.addEventListener(
"click",
function (e) {
const target = e.target.closest("a, button, [onclick]");
if (!target) return;
const text = (target.textContent || "").toLowerCase();
const hrefAttr = (target.getAttribute("href") || "").toLowerCase();
const isAllowedDownloadElement =
target.id === "downloadButton" ||
target.classList.contains("popsok") ||
target.matches(".download_link .input") ||
(text.includes("download") &&
(text.includes("mb") ||
hrefAttr.includes("/download/") ||
hrefAttr.includes("download")));
if (isAllowedDownloadElement) {
showFlash("[ALLOWED] Download button click", "success");
return;
}
const suspiciousDomains = [
"googleads",
"doubleclick",
"google.com/aclk",
"adclick",
"popup",
"/ad/",
"/ads/",
"ezoic",
"ezodn",
"googletagmanager",
"googlesyndication",
"taboola",
"outbrain",
];
const isSuspicious = suspiciousDomains.some((domain) =>
hrefAttr.includes(domain),
);
if (isSuspicious || target.hasAttribute("data-ad-link")) {
showFlash(
"[POPUP BLOCKED] Ad click intercepted: " +
hrefAttr.substring(0, 150),
"success",
);
e.preventDefault();
e.stopPropagation();
e.stopImmediatePropagation();
return false;
}
},
true,
);
const blockedScripts = [
"ezoic",
"ezodn",
"ezojs",
"doubleclick",
"googleads",
"googletagmanager",
"googletagservices",
"quantserve",
"google-analytics",
"google.com/aclk",
"facebook.com/plugins",
"google.com/pagead",
"googlesyndication",
"taboola",
"outbrain",
];
const originalAppendChild = Element.prototype.appendChild;
const originalInsertBefore = Element.prototype.insertBefore;
function shouldBlockScript(element) {
if (!element || element.tagName !== "SCRIPT") return false;
const src = (element.src || "").toLowerCase();
return blockedScripts.some((pattern) => src.includes(pattern));
}
Element.prototype.appendChild = function (element) {
if (shouldBlockScript(element)) {
showFlash("[SCRIPT BLOCKED] appendChild: " + element.src, "success");
return element;
}
return originalAppendChild.call(this, element);
};
Element.prototype.insertBefore = function (newElement, referenceElement) {
if (shouldBlockScript(newElement)) {
showFlash(
"[SCRIPT BLOCKED] insertBefore: " + newElement.src,
"success",
);
return newElement;
}
return originalInsertBefore.call(this, newElement, referenceElement);
};
const originalDocWrite = document.write;
const originalDocWriteln = document.writeln;
document.write = function (...args) {
const content = args.join("").toLowerCase();
if (blockedScripts.some((pattern) => content.includes(pattern))) {
showFlash("[SCRIPT BLOCKED] document.write", "success");
return;
}
return originalDocWrite.apply(document, args);
};
document.writeln = function (...args) {
const content = args.join("").toLowerCase();
if (blockedScripts.some((pattern) => content.includes(pattern))) {
showFlash("[SCRIPT BLOCKED] document.writeln", "success");
return;
}
return originalDocWriteln.apply(document, args);
};
/**
* Searches for a download button element using multiple selector strategies.
* @returns {Element|null} The download button element if found, otherwise null.
*/
function getDirectDownloadButton() {
const selectors = [
".download_link .input",
"#downloadButton",
"a.input.popsok",
'a[href*="download"][id="downloadButton"]',
".download-btn",
'[data-testid="download-button"]',
];
for (const selector of selectors) {
let button = document.querySelector(selector);
if (!button && selector === "a.input.popsok") {
button = Array.from(document.querySelectorAll("a")).find((el) => {
const txt = (el.textContent || "").toLowerCase();
return (
el.classList.contains("popsok") ||
(txt.includes("download") && txt.includes("mb"))
);
});
}
if (button && button.href) {
return button;
}
}
return null;
}
/**
* Attempts to find and click the download button, either by direct redirect or click event.
* @returns {boolean} true if the button was found and a click/redirect was attempted, false otherwise
*/
async function clickDownloadButton() {
const button = getDirectDownloadButton();
if (!button) return false;
showFlash("[MF] Found download button", "success");
showFlash("[MF] Text: " + (button.textContent || "").trim(), "success");
showFlash("[MF] Href: " + button.href, "success");
try {
if (button.href && /^https?:\/\//i.test(button.href)) {
showFlash("[MF] Redirecting directly to download URL", "success");
location.replace(button.href);
await sleep(8000);
try {
window.close();
} catch (e) {}
return true;
}
} catch (err) {
showFlash(
"[MF] Direct redirect failed, fallback to click:" + err.message,
"error",
);
}
try {
const clickEvent = new MouseEvent("click", {
bubbles: true,
cancelable: true,
view: window,
button: 0,
});
button.dispatchEvent(clickEvent);
await sleep(300);
try {
button.click();
showFlash("[MF] Download button clicked", "success");
} catch (e) {
showFlash("[MF] Native click failed: " + e.message, "error");
}
return true;
} catch (err) {
showFlash("[MF] Failed to trigger button: " + err.message, "error");
return false;
}
}
/**
* Waits for the download button to become available and clickable.
* Attempts to click the button repeatedly at 300ms intervals until successful or max attempts reached.
* @param {number} [maxAttempts=50] - Maximum number of attempts to find and click the download button
* @returns {void}
*/
function waitForDownloadButton(maxAttempts = 50) {
let attempts = 0;
const interval = setInterval(() => {
attempts++;
if (clickDownloadButton()) {
clearInterval(interval);
return;
}
if (attempts >= maxAttempts) {
clearInterval(interval);
showFlash(
"[MF] Download button not found after " + maxAttempts + " attempts",
"error",
);
}
}, 300);
}
if (location.href.endsWith("#bulk")) {
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", () =>
waitForDownloadButton(),
);
} else {
waitForDownloadButton();
}
originalAddEventListener.call(window, "load", async () => {
await sleep(500);
clickDownloadButton();
await sleep(1500);
clickDownloadButton();
});
} else {
if (document.readyState === "complete") {
showFlash(
"[MF] Auto click only available on bulk download pages",
"success",
);
return;
}
}
}
/**
* folder page handle
*/
if (isFolderPage) {
showFlash("[MF] Folder page detected.", "success");
/**
* Determines the delay time before opening the next batch of download tabs based on the number of remaining downloads.
* @param {number} remaining - The number of remaining download links that have not yet been opened.
* @returns {number} The delay time in milliseconds before opening the next batch of tabs.
*/
function getBatchDelay(remaining) {
if (remaining <= 0) return 0;
if (remaining <= 2) return 3000;
if (remaining <= 5) return 8000;
if (remaining <= 15) return 15000;
return 25000;
}
/**
* Opens download links from DOM elements matching the selector.
* @param {string} selector - CSS selector for list items containing download links.
*/
async function startDownload(selector) {
const listItems = [...document.querySelectorAll(selector)];
console.log("[MF] Items found:", listItems.length, "selector:", selector);
if (!listItems.length) {
if (selector.includes("file_selected")) {
showFlash("Select at least 1 file to download.", "error");
} else {
showFlash("Folder list not found yet.", "error");
}
return;
}
const urls = listItems
.map((item) => item.querySelector("a")?.href)
.filter(Boolean);
if (!urls.length) {
if (selector.includes("file_selected")) {
showFlash("No download link found from selected items.", "error");
} else {
showFlash("No downloadable links found.", "error");
}
return;
}
const batchSize = 5;
const delayPerTab = 1000;
let opened = 0;
for (let i = 0; i < urls.length; i += batchSize) {
const batch = urls.slice(i, i + batchSize);
for (const url of batch) {
window.open(url + "#bulk", "_blank");
opened++;
await sleep(delayPerTab);
}
const remaining = urls.length - (i + batch.length);
const batchDelay = getBatchDelay(remaining);
if (batchDelay > 0) {
showFlash(
`[MF] Waiting ${batchDelay / 1000}s before opening ${remaining} more tab(s)...`,
"success",
);
await sleep(batchDelay);
}
}
console.log("[MF] Opened tabs:", opened);
showFlash(`[MF] Opened ${opened} tabs total`, "success");
}
/**
* Injects a dropdown button with download options into the page.
* Replaces the upgrade button frame with a wrapper containing a "DOWNLOAD ▼" button
* that opens a menu with options to download all files or selected files.
* @returns {void}
*/
function injectButton() {
if (document.getElementById("mf-download-dropdown")) return;
const upgradeButtonFrame = document.querySelector(
".upgrade_button_frame",
);
if (!upgradeButtonFrame || !upgradeButtonFrame.parentNode) return;
const wrapper = document.createElement("div");
wrapper.id = "mf-download-dropdown";
wrapper.style.position = "relative";
wrapper.style.display = "inline-block";
wrapper.style.marginRight = "10px";
const button = document.createElement("button");
button.type = "button";
button.textContent = "DOWNLOAD ▼";
button.classList.add("Btn", "Btn--greenUpgrade");
button.style.backgroundColor = "#33CC66";
button.style.color = "#222835";
button.style.border = "none";
button.style.cursor = "pointer";
const menu = document.createElement("div");
menu.style.position = "absolute";
menu.style.top = "100%";
menu.style.left = "0";
menu.style.display = "none";
menu.style.minWidth = "180px";
menu.style.background = "#fff";
menu.style.border = "1px solid #ccc";
menu.style.boxShadow = "0 2px 8px rgba(0,0,0,0.15)";
menu.style.zIndex = "9999";
/**
* Creates a styled menu item element with hover and click behavior.
* @param {string} label - The text to display in the menu item.
* @param {Function} onClick - The callback function to execute when the item is clicked.
* @returns {HTMLDivElement} A styled div element configured as a menu item.
*/
function createMenuItem(label, onClick) {
const item = document.createElement("div");
item.textContent = label;
item.style.padding = "10px 12px";
item.style.cursor = "pointer";
item.style.whiteSpace = "nowrap";
item.addEventListener("mouseenter", () => {
item.style.background = "#f2f2f2";
});
item.addEventListener("mouseleave", () => {
item.style.background = "#fff";
});
item.addEventListener("click", (e) => {
e.stopPropagation();
menu.style.display = "none";
onClick();
});
return item;
}
const downloadAllItem = createMenuItem("Download All", () => {
startDownload("#main_list > li");
});
const downloadSelectedItem = createMenuItem("Download Selected", () => {
const selectedSelector = '#main_list > li[id^="file"].file_selected';
if (!document.querySelector(selectedSelector)) {
showFlash("Select at least 1 file to download.", "error");
return;
}
startDownload(selectedSelector);
});
button.addEventListener("click", (e) => {
e.stopPropagation();
menu.style.display = menu.style.display === "block" ? "none" : "block";
});
document.addEventListener("click", () => {
menu.style.display = "none";
});
menu.appendChild(downloadAllItem);
menu.appendChild(downloadSelectedItem);
wrapper.appendChild(button);
wrapper.appendChild(menu);
upgradeButtonFrame.parentNode.replaceChild(wrapper, upgradeButtonFrame);
showFlash("[MF] Download dropdown injected.", "success");
}
/**
* Waits for the folder UI to be ready by repeatedly attempting to inject the button.
* @param {number} [maxAttempts=60] - The maximum number of attempts to inject the button before stopping.
* @returns {void}
*/
function waitForFolderUI(maxAttempts = 60) {
let attempts = 0;
const interval = setInterval(() => {
attempts++;
injectButton();
if (
document.getElementById("mf-download-all-btn") ||
attempts >= maxAttempts
) {
clearInterval(interval);
}
}, 500);
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", waitForFolderUI);
} else {
waitForFolderUI();
}
window.addEventListener("load", async () => {
await sleep(500);
injectButton();
await sleep(1500);
injectButton();
});
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment