您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds direct-download buttons and links for Pixeldrain files using an alternate proxy — inspired by 'Pixeldrain Download Bypass' by hhoneeyy and MegaLime0
// ==UserScript== // @name Pixeldrain DL Bypass // @namespace https://greasyfork.org/users/821661 // @version 1.5.2 // @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", ""), jDownloaderURL: "http://127.0.0.1:9666/flash/addcnl", preferences: { scrollbarNames: { state: GM_getValue("scrollbar-names", false), effect: () => GM_addStyle(".container-names { overflow: scroll; } .file-name { overflow: initial }"), }, directDownload: { state: GM_getValue("direct-download", false), }, }, viewer_data: unsafeWindow.viewer_data, api_response: unsafeWindow.viewer_data.api_response, dataType: unsafeWindow.viewer_data.type, }; const selectedProxy = PDLB_CONFIG.customBypassURL || PDLB_CONFIG.defaultBypassURL; function createButton(iconName, title, text) { const template = document.createElement("template"); template.innerHTML = ` <button class="toolbar_button svelte-jngqwx" title="${title}"> <i class="icon">${iconName}</i> <span class="svelte-jngqwx">${text}</span> </button> `; return template.content.firstElementChild; } 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" style="max-height: 80%; max-width: 80%; "> <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 template = document.createElement("template"); template.innerHTML = MODAL_HTML; const modalElement = template.content.firstElementChild; modalElement.addEventListener("click", (event) => { if (event.target.matches(".background") || event.target.closest(".close-button")) { modalElement.remove(); } }); document.body.insertAdjacentElement("afterbegin", modalElement); return () => modalElement.remove(); } function downloadFile(fileName, fileID, el) { return new Promise((resolve, reject) => { const url = `https://${selectedProxy}/${fileID}`; if (PDLB_CONFIG.preferences.directDownload.state) { window.open(url, "_blank"); return resolve(); } GM_xmlhttpRequest({ url, responseType: "blob", onload(event) { resolve(event); if (event.status !== 200) { showModal("Download error", `The server probably blocked download of the file.`); 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 { if (file.availability || file.availability_message) { showModal( file.availability, `Error on download file: ${file.name}<br>Server availability message: ${file.availability_message}.<br>Trying download of others files.`, ); continue; } const res = await downloadFile(file.name, file.id, el); if (res.loaded === 0) { throw new Error("0 bytes loaded from response."); } } catch (error) { console.error(`Failed to download ${file.name}:`, error); showModal("Download error", `Failed to download ${file.name}.`); } } } function copyBypassURL(fileID) { const url = `https://${selectedProxy}/${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.")); } async function openBypassURL(file) { const w = window.open("about:blank", "_blank"); const finalURL = file.proxyFinalURL || (await getFinalURL(`https://${selectedProxy}/${file.id}`)); w.document.write(` <html style="background: #000;"> <body style="margin:0"> <video src="${finalURL}" controls autoplay style="width:100%;height:100%"></video> </body> </html> `); w.document.close(); } function handleSingleFile(separator, fileData) { const { name, id } = fileData; const downloadButton = createButton("download", "Bypass download", "Download bypass"); const openButton = createButton("open_in_new", "Open bypass URL", "Open bypass"); const copyButton = createButton("content_copy", "Copy bypass URL", "Copy bypass"); const sendToJDownloaderButton = createButton("add_link", "Add link to JDownloader", "Add link to JDownloader"); downloadButton.addEventListener("click", () => downloadFile(name, id, downloadButton)); openButton.addEventListener("click", async () => { openBypassURL(fileData); }); copyButton.addEventListener("click", () => copyBypassURL(id)); sendToJDownloaderButton.addEventListener("click", async () => { sendToJDownloader(fileData.proxyFinalURL); }); setBypassURL([fileData]).then(() => document.body.classList.add("final-urls-loaded")); separator.insertAdjacentElement("afterend", downloadButton); downloadButton.insertAdjacentElement("afterend", openButton); openButton.insertAdjacentElement("afterend", copyButton); copyButton.insertAdjacentElement("afterend", sendToJDownloaderButton); sendToJDownloaderButton.insertAdjacentElement("afterend", separator.cloneNode()); } function handleFileList(separator, listData) { const availableFiles = []; const bypassURLS = []; let filesLinkHTML = ""; for (const file of listData.files) { if (file.availability || file.availability_message) continue; availableFiles.push(file); bypassURLS.push(`https://${selectedProxy}/${file.id}`); filesLinkHTML += ` <a class="file-name" target="_blank" rel="noopener noreferrer" title="${file.name}" href="https://${selectedProxy}/${file.id}"> ${file.name} </a>`; } const containerFileURLS = `<div class="indent container-names" style="display: flex; flex-direction: column;justify-content: center;align-items: center;">${filesLinkHTML}</div>`; const containerBypassURLS = `<pre class="indent" style="padding-inline: .5rem; overflow: initial;">${bypassURLS.join("\n")}</pre>`; const dlSelectedButton = createButton("download", "Bypass download selected file", "Download selected"); const dlAllButton = createButton("download", "Bypass download all files", "Download all"); const openButton = createButton("open_in_new", "Open bypass URL", "Open bypass"); const copyButton = createButton("content_copy", "Copy bypass url", "Copy bypass"); const showUrlsButton = createButton("link", "Show bypass URLs", "Show bypass"); const sendAllToJDButton = createButton("add_link", "Add links to JDownloader", "Add links to JDownloader"); const sendSelectedToJDButton = createButton("add_link", "Add link to JDownloader", "Add link to JDownloader"); dlSelectedButton.addEventListener("click", () => { const selectedFile = listData.files.find((file) => file.selected); if (selectedFile.availability || selectedFile.availability_message) { showModal(selectedFile.availability, selectedFile.availability_message); return; } downloadFile(selectedFile.name, selectedFile.id, dlSelectedButton); }); dlAllButton.addEventListener("click", () => massiveDownload(listData.files, dlAllButton)); openButton.addEventListener("click", async () => { const selectedFile = listData.files.find((file) => file.selected); openBypassURL(selectedFile); }); copyButton.addEventListener("click", () => { const selectedFile = listData.files.find((file) => file.selected); copyBypassURL(selectedFile.id); }); showUrlsButton.addEventListener("click", () => showModal("Bypass URLs", containerFileURLS + containerBypassURLS)); sendAllToJDButton.addEventListener("click", async () => { const urls = listData.files.map((file) => file.proxyFinalURL).join("\r\n"); sendToJDownloader(urls); }); sendSelectedToJDButton.addEventListener("click", async () => { const selectedFile = listData.files.find((file) => file.selected); sendToJDownloader(selectedFile.proxyFinalURL); }); setBypassURL(availableFiles).then(() => document.body.classList.add("final-urls-loaded")); separator.insertAdjacentElement("afterend", dlSelectedButton); dlSelectedButton.insertAdjacentElement("afterend", dlAllButton); dlAllButton.insertAdjacentElement("afterend", openButton); openButton.insertAdjacentElement("afterend", copyButton); copyButton.insertAdjacentElement("afterend", showUrlsButton); showUrlsButton.insertAdjacentElement("afterend", sendSelectedToJDButton); sendSelectedToJDButton.insertAdjacentElement("afterend", sendAllToJDButton); sendAllToJDButton.insertAdjacentElement("afterend", separator.cloneNode()); } 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(); }); GM_registerMenuCommand(`${PDLB_CONFIG.preferences.directDownload.state ? "ON" : "OFF"}: Direct download`, () => { GM_setValue("direct-download", !PDLB_CONFIG.preferences.directDownload.state); unsafeWindow.location.reload(); }); GM_registerMenuCommand(`${PDLB_CONFIG.preferences.scrollbarNames.state ? "ON" : "OFF"}: Horizontal scrollbar for long names`, () => { GM_setValue("scrollbar-names", !PDLB_CONFIG.preferences.scrollbarNames.state); unsafeWindow.location.reload(); }); } async function setBypassURL(availableFiles) { const promises = availableFiles.map(async (file) => { const finalURL = await getFinalURL(`https://${selectedProxy}/${file.id}`); file.proxyFinalURL = finalURL.replace("?download", ""); }); await Promise.all(promises); } function getFinalURL(url) { return new Promise((resolve, reject) => { GM_xmlhttpRequest({ url, method: "HEAD", onload(event) { resolve(event.finalUrl); }, onerror: (ev) => { console.error("Error getting final URL", ev); showModal("Error getting final URL", "The proxy is probably down or blocking the request."); reject(ev); }, }); }); } function sendToJDownloader(urls) { const data = { urls, source: urls, }; GM_xmlhttpRequest({ method: "POST", url: PDLB_CONFIG.jDownloaderURL, headers: { "Content-Type": "application/json", }, data: JSON.stringify(data), onerror(ev) { console.error("Error sending to jDownloader", ev); showModal("Error sending to jDownloader", "jDownloader is probably closed or listening on another port."); }, }); } 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"], [title="Add link to JDownloader"], [title="Open 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; transition: 0.3s; } [title="Add link to JDownloader"], [title="Add links to JDownloader"] { display: none; } .final-urls-loaded :where([title="Add link to JDownloader"], [title="Add links to JDownloader"]) { display: block; } .file-name { max-width: 550px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; } `); 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(); for (const key in PDLB_CONFIG.preferences) { const state = PDLB_CONFIG.preferences[key].state; if (state) PDLB_CONFIG.preferences[key].effect?.(); } } init();