// ==UserScript==
// @name Pixeldrain DL Bypass
// @namespace https://greasyfork.org/users/821661
// @version 1.3
// @description Adds direct-download buttons and links for Pixeldrain files using an alternate proxy — inspired by 'Pixeldrain Download Bypass' by hhoneeyy and MegaLime0
// @author hdyzen
// @match https://pixeldrain.com/*
// @match https://pixeldrain.net/*
// @icon https://www.google.com/s2/favicons?domain=pixeldrain.com/&sz=64
// @grant GM_xmlhttpRequest
// @grant GM_registerMenuCommand
// @grant GM_addStyle
// @grant GM_getValue
// @grant GM_setValue
// @license GPL-3.0-only
// ==/UserScript==
const PDLB_CONFIG = {
defaultBypassURL: "pd.1drv.eu.org",
customBypassURL: GM_getValue("custom_proxy", ""),
viewer_data: unsafeWindow.viewer_data,
api_response: unsafeWindow.viewer_data.api_response,
dataType: unsafeWindow.viewer_data.type,
};
function createElementWithListener(html, type, listener) {
const div = document.createElement("div");
div.style.setProperty("display", "contents", "important");
div.innerHTML = html;
div.addEventListener(type, listener);
return div;
}
function createButtonHTML(iconName, title, text, type = "") {
return `
<button class="toolbar_button svelte-jngqwx" title="${title}" type="${type}">
<i class="icon">${iconName}</i>
<span class="svelte-jngqwx">${text}</span>
</button>
`;
}
function showModal(title, content, extraContent = "") {
const MODAL_HTML = `
<div class="background svelte-1f8gt9n" style="z-index: 10001;" role="dialog">
<div class="window svelte-1f8gt9n" role="dialog" aria-modal="true">
<div class="header svelte-1f8gt9n">
<span class="title svelte-1f8gt9n" style="padding-inline: calc(2rem + 32px) 2rem;">${title}</span>
<button class="button svelte-1ef47mx round close-button">
<i class="icon">close</i>
</button>
</div>
<div class="body svelte-1f8gt9n" style="padding: 1rem;">
<div class="container svelte-1j8hfe6" style="display: flex; flex-direction: row;justify-content: center;align-items: center;">
${content}
</div>
<div class="container svelte-1j8hfe6" style="display: flex; flex-direction: row;justify-content: center;align-items: center;">
${extraContent}
</div>
</div>
</div>
</div>
`;
const modalElement = createElementWithListener(MODAL_HTML, "click", (event) => {
if (event.target.matches(".background") || event.target.closest(".close-button")) {
modalElement.remove();
}
});
document.body.insertAdjacentElement("afterbegin", modalElement);
}
function downloadFile(fileName, fileID, el) {
return new Promise((resolve, reject) => {
const selectedDomain = PDLB_CONFIG.customBypassURL || PDLB_CONFIG.defaultBypassURL;
const url = `https://${selectedDomain}/${fileID}`;
GM_xmlhttpRequest({
url,
responseType: "blob",
onload(event) {
resolve(event);
if (event.status !== 200) {
showModal("Download error", "The server probably blocked this download.");
return;
}
const a = document.createElement("a");
a.target = "_blank";
a.href = URL.createObjectURL(event.response);
a.download = fileName;
a.click();
el.style.setProperty("--loaded", "0");
},
onerror(event) {
reject(event);
},
onprogress(event) {
el.style.setProperty("--loaded", `${(event.loaded * el.clientWidth) / event.total}px`);
},
});
});
}
async function massiveDownload(files, el) {
for (const file of files) {
try {
await downloadFile(file.name, file.id, el);
} catch (error) {
console.error(`Failed to download ${file.name}:`, error);
showModal("Download error", `Failed to download ${file.name}.`);
}
}
}
function copyBypassURL(fileID) {
const selectedDomain = PDLB_CONFIG.customBypassURL || PDLB_CONFIG.defaultBypassURL;
const url = `https://${selectedDomain}/${fileID}`;
navigator.clipboard
.writeText(url)
.then(() => showModal("URL copied", "The bypass URL has been copied to your clipboard."))
.catch(() => showModal("Copy failed", "Could not copy the URL. Please copy it manually."));
}
function handleSingleFile(separator, fileData) {
const { name, id } = fileData;
const downloadButtonHTML = createButtonHTML("download", "Bypass download", "Download bypass");
const copyButtonHTML = createButtonHTML("content_copy", "Copy bypass url", "Copy bypass");
const downloadButton = createElementWithListener(downloadButtonHTML, "click", () => downloadFile(name, id, downloadButton.firstElementChild));
const copyButton = createElementWithListener(copyButtonHTML, "click", () => copyBypassURL(id));
separator.insertAdjacentElement("afterend", downloadButton);
downloadButton.insertAdjacentElement("afterend", copyButton);
}
function handleFileList(separator, listData) {
const selectedDomain = PDLB_CONFIG.customBypassURL || PDLB_CONFIG.defaultBypassURL;
const availableFiles = listData.files.filter((file) => file.availability === "");
const fileUrls = availableFiles.map((file) => `<a href="https://${selectedDomain}/${file.id}">${file.name}</a>`).join("<br>");
const containerFileUrls = `<div class="indent" style="display: flex; flex-direction: column;justify-content: center;align-items: center;">${fileUrls}</div>`;
const bypassUrls = availableFiles.map((file) => `https://${selectedDomain}/${file.id}`);
const containerBypassUrls = `<pre class="indent" style="padding-inline: .5rem;">${bypassUrls.join("\n")}</pre>`;
const dlSelectedButtonHTML = createButtonHTML("download", "Bypass download selected file", "Download selected");
const dlAllButtonHTML = createButtonHTML("download", "Bypass download all files", "Download all");
const copyButtonHTML = createButtonHTML("content_copy", "Copy bypass url", "Copy bypass");
const showUrlsButtonHTML = createButtonHTML("link", "Show bypass URLs", "Show bypass");
const JDownloaderFormHTML = createJDownloaderForm(availableFiles);
const dlAllButton = createElementWithListener(dlAllButtonHTML, "click", () => massiveDownload(availableFiles, dlAllButton.firstElementChild));
const showUrlsButton = createElementWithListener(showUrlsButtonHTML, "click", () => showModal("Bypass URLs", containerFileUrls + containerBypassUrls, JDownloaderFormHTML));
const copyButton = createElementWithListener(copyButtonHTML, "click", () => {
const selectedFile = listData.files.find((file) => file.selected);
copyBypassURL(selectedFile.id);
});
const dlSelectedButton = createElementWithListener(dlSelectedButtonHTML, "click", () => {
const selectedFile = listData.files.find((file) => file.selected);
if (selectedFile.availability !== "") {
showModal(selectedFile.availability, selectedFile.availability_message);
return;
}
downloadFile(selectedFile.name, selectedFile.id, dlSelectedButton.firstElementChild);
});
separator.insertAdjacentElement("afterend", dlSelectedButton);
dlSelectedButton.insertAdjacentElement("afterend", dlAllButton);
dlAllButton.insertAdjacentElement("afterend", copyButton);
copyButton.insertAdjacentElement("afterend", showUrlsButton);
}
function registerCommands() {
GM_registerMenuCommand(`[Current proxy]: ${PDLB_CONFIG.customBypassURL || PDLB_CONFIG.defaultBypassURL}`, () => {});
GM_registerMenuCommand("Set custom proxy", () => {
const proxyDomain = prompt("Set your custom proxy", GM_getValue("custom_proxy", ""));
GM_setValue("custom_proxy", proxyDomain || "");
unsafeWindow.location.reload();
});
}
function createJDownloaderForm(files) {
const urlsString = files.map((file) => `https://gamedriveorg.pd28.workers.dev/api/file/${file.id}`).join("\r\n");
const addLinkHTML = createButtonHTML("add_link", "Add links to JDownloader", `Add links to JDownloader`, "submit");
const formHTML = `
<form action="http://127.0.0.1:9666/flash/add" target="hidden" method="POST">
<input type="hidden" name="urls" value="${urlsString}">
${addLinkHTML}
</form>
`;
return formHTML;
}
function init() {
if (!PDLB_CONFIG.viewer_data) {
console.warn("Viewer data not found. Script may not function correctly.");
return;
}
const separator = document.querySelector(".toolbar > .separator.svelte-jngqwx");
if (!separator) {
console.warn("Toolbar separator not found. Cannot add buttons.");
return;
}
GM_addStyle(`
.file_preview_row:has(.gallery) :where([title="Bypass download selected file"], [title="Copy bypass url"]) { display: none !important; }
[title="Bypass download"], [title="Bypass download selected file"], [title="Bypass download all files"] { box-shadow: inset var(--highlight_background) var(--loaded, 0) 0; }
`);
switch (PDLB_CONFIG.dataType) {
case "file":
handleSingleFile(separator, PDLB_CONFIG.api_response);
break;
case "list":
handleFileList(separator, PDLB_CONFIG.api_response);
break;
default:
console.warn(`File type "${PDLB_CONFIG.dataType}" not supported.`);
}
registerCommands();
}
init();