// ==UserScript== // @name pixeldrain improved (sort by size, markers and modal) // @namespace Violentmonkey Scripts // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAQAAAAAYLlVAAAACXBIWXMAAA3XAAAN1wFCKJt4AAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAAggSURBVHhelFlrcFXVGV25PAIJJEICgdHIywSTCKWiBAVGpoq0VSFWIig1MErbGWsF0aDjKB2itpUGtJYWq3XEEQGBClP6EBWpVMrTFEJCIeERHBXEG4gJkaSUrP44e39773PPOZes/ePss761v/2dux/n7O+mEJ1EPq7FSOThSmQjA90BtKMZcZxAPaqxF8eSOXCR0okAbsKduBnXJFHtw2ZswK4kKgNeSsniAtawM9jLh5iW1C94CQFk8jl+nay/QJzi4+yWzH+yIXgQFcjykxdRj6P4EmfQCiAdWcjBUOQjlti+AU9idSJtISK6PG71P1Q1KzmFVwTKczmFS4NG6k/sF95LqIH38YLtpZnLODbcj1XG8Xc854YQ53fD5GFenrfbt3JR1EMElBw+yzY3iEeDpcHt37Jbvs6BId3E2JM9GQux5nKlG8KSIFnQJHwHd+pqI+Zgo8/cH+MwBldjCPoiFUAbzqABh7AL2/GVT1uKV5FpbpfjQfiREJMV9jb2d0wpnMGNbGUYWrmBd/vcXc6dtuTX/v783T9ntG/5THN5zN9jII7wIV/Ldbb5p1EBTDW6VxzD5MCNsIaVXMKDAZb9vNlp/4ZtLA4LIJsdWrPaaf5iYg8knxf70kB7peNjgzE0sXtwAB9pxW6LTDe0gy2O+22Bmg+Yamn2G8PaoADu1tZv2FvIPjwc5JnkD5wA7glR1Vi+sthuDDf5A0jhWW0zm1Z31gU49fAdJ4Dvh+pq2UVUJYY+4Q+gXFvWW24/FvVsDudoLrEc/8oJ4AXL8kfeyDyWyk/+oaX7q5HNsgPowhaPvchMES9Wyk+ZIVyZtG/jCGG/bb02nrS6+7fiKoTpJzqetAOYo1nzXNeJstRyCf5D+HbOZwELWM7/CfcfR1ss/EjhXhKOJSYAtcgvsJcIj4hugOP0cUZhmaNNYbPia4W7zKz17QQRA1CIIm9bfhPn1AZ9L4bJZt3L2boTvk4cZDt3aeimaoW4S9WasEabb8SVAAgu0iGNljgbrKd6wXmqzxmFc9Z8AR+xLPXCjjPkY94Q7PHujovkFrqYrfg0bhJuN8s5nnnM5wQ+wb0Wr19gt5sfmyQ5IfEhthJgltb9RgRr6MdWLuJLPKnuTie888B7eEZZv+bLXMi/Jfh4Q7Qva6qN6dYeove2bjJ1glHre0nrMjBi2yLJRvl0mW7IiTF8S8+Jvep6A3ojHE0Yi9OBlpMolkkchL64XtU+MeSoGPK92mf4VHFjEIUZaAm1ncXMUBsAFKvrUfMIw2PI9WpHRFYgtfWYhCLMwH5hPsFmROHPOCD13ShFEb6HTcIUqitxVFOD5C25SsbyPTU8S63xVQuFPwkcfbs8rJTbLO4Vxf1FGPlG2hNDhhdKq8TpbTWfYz4M7lfX5GfOnQCADpRZ3I8RBwD0FUZ6y4gh1UehBwBgC2wcwCkADJl+Nr4EABxDg8P+EwCQJvf/1ZUeMaR4NXOu6wBgR6uU8N4byeAp3O1be+uQ+xSpxXQwpom3lCY5+3oZLgMQQ38kQw4AYABKLG4QJgCAtX5SdeVCTLNm7X+lJO8rZ8B4LFe16CUKmKW2QlZ9Lt5Vv685tshhpaUrGr3aFWI8rq6jUIeVaMAYTBPbHLyKaDygrpnYjdWowlUoQ0/Fac/Qax+Iy0koLt9uDzAK7ve+v9wW2faHSpVqMh6vxVDvhZKF4SqojxGFt6257EcGVoXaAGC7uhbqtQ/Ux1Ct63p8D0cmurKwA30CLf2wwzgOwCEZAmsmVcfUzgHgFmHXwY8qLJfvpZGoNcdnwTTUqK22A2vxe/wrQbFWapMMuQsED3jD0SSvy6G+sZur+BzrlLSd81jMwRzMsXyEO4Q/yKuU+l6fl1zFd9Of4OQe74tIf3/zdplM+n1Akn+wJlmMpxmFNuZY6qcsyyZhpxmywgvgWn3/gYhGWE2HWy7dI0gi3nG0GdZh7GphrXNkkf4sl2/wYSJbJSr7mcAFjMJvHS3k2+p1YQqMuJbQAfxMcxtEmMbzirvDcbnZOOAa3scyJ/1Q7WhHKbbFOiX/3YjnmAB6mJSWOcPcqpi64OOlbCvg/RZrZ0f01JwojDlvscWb89ryc83XWA6eFq6EA5gn9yS50tK5SZhKFrI/J8vRttzS1RvZAo/Slq4mt2gfL5eJ3jrbk6Qv82j/MiRl+MgXLVWFETQxxQ0AnGWsY6xGwekZcrITwNQQlZ2mGW8b5GBhe5F8WjOzLHp+ol+SK5wAzJqx8bClGMhvjOEjY7C9DDCKw052Z6I9dgJzOpoZYD3EcZaHdB43pov289kBgKVGtY/plqErf+HmrkmSKzid0/lmAt/OZ5wEbqab5Jti9+kG4CSp6zjYMQ3iUjb6+0pAnJWy63tlmJvgrHCMAana1Ubbwtt8xkzO5jp+4e+VJHmSb3OWczwHwan22NsnVFWCktUbMdXcLEE5/JruGIEiDEEOegI4j1M4joOoQbtP1wWVmGcT61EKPxJ+AdCXrj/kJXM6Xe7yT90VQbKw1r90225JGIzocgc/pA/PBkvDfcz0b35VfJR5oXJd8lku6TnBec4IaxDlayjf93sid3Ixp7HA96dgOgtYysXufwMa7/qWk1OS/W33Izwj5xMHccRxVv1t1wfZvvyY4BSewmvBJoWIX8ArvbiQ8aAHS4o4Fzq7WWBJ1r1XMjgvcWAjUcW5CVtCYEk2BDZuQAluxagkqn14DxuxI4lK0JkAPAzBaFyDPAxCNnqjB4A2NKMRJ1CHGlRZB8BLwv8HAJgRfVe9mOrfAAAAAElFTkSuQmCC // @match https://pixeldrain.com/l/* // @match https://pixeldrain.com/api/file/* // @version 1.1.4 // @grant GM_addStyle // @grant GM_getValue // @grant GM_setValue // @grant GM_registerMenuCommand // @author dummy_mole // @license GNU GPLv3 // @description Improves the user experience on pixeldrain by adding a sort by size button, markers on viewed files and file playback in a modal window. // @downloadURL none // ==/UserScript== (async () => { 'use strict'; //===================================script config panel part==================================== const defaultConfig = { "auto_sort_file": false, "show_file_size": true, "seen_file": false, "viewing_file_method": "2" }; function createConfigPanel() { // DOM creation const configPanel = `
`; document.body.insertAdjacentHTML('afterbegin', configPanel); //--------------------------------------------------------------------------------------------- function slideOutAndRemove(element, classOut, classIn) { element.classList.remove(classOut); element.classList.add(classIn); setTimeout(() => element.remove(), 1000); } const configPanelContainer = document.querySelector('.config-panel-container'); const autoSortCheckbox = document.querySelector('#auto-sort'); const showFileSizeCheckbox = document.querySelector('#show-filesize'); const seenFileCheckbox = document.querySelector('#seen-file'); const viewedFileMethodSelect = document.querySelector('#file-viewing-method'); const saveBtn = document.querySelector('.save-btn'); const resetBtn = document.querySelector('.reset-btn'); const cancelBtn = document.querySelector('.cancel-btn'); // Load configuration values from script's local storage or use default values let config = JSON.parse(GM_getValue("pixeldrain_cfg") || defaultConfig); // Updates user interface elements with current configuration values autoSortCheckbox.checked = config.auto_sort_file; showFileSizeCheckbox.checked = config.show_file_size; seenFileCheckbox.checked = config.seen_file; viewedFileMethodSelect.value = config.viewing_file_method; // Updates configuration when user interface elements change autoSortCheckbox.onchange = function () { config.auto_sort_file = this.checked; }; showFileSizeCheckbox.onchange = function () { config.show_file_size = this.checked; }; seenFileCheckbox.onchange = function () { config.seen_file = this.checked; }; viewedFileMethodSelect.onchange = function () { config.viewing_file_method = this.value; }; // Saves configuration to script's local storage when user clicks "Save" saveBtn.onclick = function () { GM_setValue("pixeldrain_cfg", JSON.stringify(config)); location.reload(); }; // Resets the configuration to default values when the user clicks on "Reset". resetBtn.onclick = function () { config = defaultConfig; autoSortCheckbox.checked = defaultConfig.auto_sort_file; showFileSizeCheckbox.checked = defaultConfig.show_file_size; seenFileCheckbox.checked = defaultConfig.seen_file; viewedFileMethodSelect.value = defaultConfig.viewing_file_method; GM_setValue("pixeldrain_cfg", JSON.stringify(defaultConfig)); location.reload(); }; // Cancels changes made to the configuration when the user clicks on "Cancel". cancelBtn.onclick = function () { slideOutAndRemove(configPanelContainer, "slide-in-top", "slide-out-top"); }; //------------------------------------config panel css style----------------------------------- const configPanelStyle = `.config-panel-container{position:fixed!important;top:10px;right:10px;z-index:10001;display:flex;flex-direction:column;min-width:250px!important;max-width:320px!important;background:linear-gradient(0deg,#141617 0,rgba(27,27,28,.9) 50%,rgba(33,34,36,.9) 100%)!important;box-shadow:6px 6px 5px #00000069!important;padding:5px 15px!important;border:1px solid #282828!important;border-radius:5px!important;font-family:inherit;backdrop-filter:blur(15px);width:265px}.config-panel-title{margin:10px auto;padding-bottom:5px;color:#159cff!important;font-size:20px!important;font-weight:600}#file-viewing-method,.panel{color:#aaa!important}.auto-sort-container,.seen-file-container,.show-filesize-container,.watch-file-method{margin:10px auto}.separator{display:block;width:98%;height:1px;background:#fdfdfd0d}.validation-buton-container{display:flex;justify-content:space-evenly;margin:10px auto}.validation-buton-container>button{display:block;font-size:16px!important;color:#f5f5f5!important;background:#0087ff;border:transparent!important;border-radius:3px!important;height:30px!important;padding:0 10px!important;width:66px;box-shadow:unset!important}#file-viewing-method{background:#2d2d2d!important;border-radius:5px!important;border:1px solid #424242!important;width:70px!important;height:25px!important;text-align:center!important;padding:unset!important;box-shadow:unset!important}#file-viewing-method>option{background:#2d2d2d!important;color:#aaa!important}.cancel-btn{background:#4a4949!important}.slide-in-top{-webkit-animation:.9s cubic-bezier(.25,.46,.45,.94) both slide-in-top;animation:.9s cubic-bezier(.25,.46,.45,.94) both slide-in-top}.slide-out-top{-webkit-animation:.9s cubic-bezier(.55,.085,.68,.53) both slide-out-top;animation:.9s cubic-bezier(.55,.085,.68,.53) both slide-out-top}@-webkit-keyframes slide-in-top{0%{-webkit-transform:translateY(-1000px);transform:translateY(-1000px);opacity:0}75%{-webkit-transform:translateY(20px);transform:translateY(20px)}100%{-webkit-transform:translateY(0);transform:translateY(0);opacity:1}}@keyframes slide-in-top{0%{-webkit-transform:translateY(-1000px);transform:translateY(-1000px);opacity:0}75%{-webkit-transform:translateY(20px);transform:translateY(20px)}100%{-webkit-transform:translateY(0);transform:translateY(0);opacity:1}}@-webkit-keyframes slide-out-top{0%{-webkit-transform:translateY(0);transform:translateY(0);opacity:1}25%{-webkit-transform:translateY(20px);transform:translateY(20px)}100%{-webkit-transform:translateY(-1000px);transform:translateY(-1000px);opacity:0}}@keyframes slide-out-top{0%{-webkit-transform:translateY(0);transform:translateY(0)}25%{-webkit-transform:translateY(20px);transform:translateY(20px)}100%{-webkit-transform:translateY(-1000px);transform:translateY(-1000px)}}`; GM_addStyle(configPanelStyle); } //======================================Pixeldrain Part========================================== const URL = location.href; const API = 'https://pixeldrain.com/api/list/'; const descendingIcon = ``; const ascendingIcon = ``; const downloadIcon = ``; //-----------------------------------Only active on album pages----------------------------------- if (/\/l\/(?![^\/]*item).*$/.test(URL)) { GM_registerMenuCommand("Pixeldrain configuration", createConfigPanel); if (!GM_getValue("pixeldrain_cfg")) GM_setValue("pixeldrain_cfg", JSON.stringify(defaultConfig)); const { auto_sort_file, show_file_size, seen_file, viewing_file_method } = JSON.parse(GM_getValue("pixeldrain_cfg")); const formatFileSize = bytes => { const units = ['o', 'Ko', 'Mo', 'Go', 'To', 'Po', 'Eo', 'Zo', 'Yo']; const exponent = Math.min(Math.floor(Math.log(bytes) / Math.log(1024)), units.length - 1); const size = (bytes / Math.pow(1024, exponent)).toFixed(2); return `${size} ${units[exponent]}`; }; //----------------------------sorting function (by size)---------------------------------------- const sortByFileSize = (nodeList, targetContainer) => { const array = [...nodeList]; const compare = (a, b) => +a.dataset.size - +b.dataset.size; const sortButton = document.createElement('button'); sortButton.className = "toolbar_button sort-button"; sortButton.innerText = "Sort files"; const sortIconContainer = document.createElement('div'); sortIconContainer.className = "sort-icon-container"; sortIconContainer.insertAdjacentHTML("afterbegin", ascendingIcon); sortButton.prepend(sortIconContainer); let reverse = false; sortButton.addEventListener('click', () => { reverse = !reverse; array.sort(compare); if (reverse) { array.reverse(); } sortIconContainer.innerHTML = ""; sortIconContainer.insertAdjacentHTML("afterbegin", reverse ? descendingIcon : ascendingIcon); const parentNode = nodeList[0].parentNode; parentNode.innerHTML = ''; array.forEach(element => parentNode.appendChild(element)); }); targetContainer.appendChild(sortButton); }; //----------------------------------------Modal------------------------------------------------- const body = document.body; const fileAPIUrl = 'https://pixeldrain.com/api/file/'; // modal function const modal = (url, file) => { const fileLink = url + file.dataset.id; const fileType = file.dataset.type; const fileTypeShort = fileType.split("/")[0]; if (!["video", "audio", "image"].includes(fileTypeShort)) { const directDL = document.createElement('a'); directDL.href = fileLink; directDL.download = ""; directDL.click(); return; } const modalContainer = document.createElement('div'); modalContainer.className = "modal-container"; const modalFileContainer = document.createElement('div'); modalFileContainer.className = "modal-file-container"; let tag; if (fileTypeShort === "video") { const tagType = document.createElement('video'); tagType.controls = true; tagType.autoplay = true; tagType.src = fileLink; tag = tagType; } if (fileTypeShort === "audio") { const tagType = document.createElement('audio'); tagType.controls = true; tagType.autoplay = true; tagType.setAttribute('playsinline', ""); const source = document.createElement('source'); source.src = fileLink; source.type = fileType; tagType.appendChild(source); tag = tagType; } if (fileTypeShort === "image") { const tagType = document.createElement('img'); tagType.src = fileLink; tag = tagType; } const downloadBtn = document.createElement('a'); downloadBtn.className = "download-file-btn"; downloadBtn.download = ""; downloadBtn.innerText = "Download"; downloadBtn.href = fileLink; downloadBtn.insertAdjacentHTML('afterbegin', downloadIcon); modalContainer.addEventListener('click', e => { const clickedElement = e.target; if (clickedElement.matches('.modal-file-container, .download-file-btn')) modalContainer.remove(); }); modalFileContainer.appendChild(tag); modalContainer.appendChild(modalFileContainer); modalFileContainer.appendChild(downloadBtn); body.appendChild(modalContainer); }; //----------------------------------------event handling---------------------------------------- // event delegation to manage actions on clicked files const gallery = document.querySelector('.gallery'); gallery.addEventListener('click', e => { if (viewing_file_method === "3") e.preventDefault(); const file = e.target.closest('a.file'); if (!file) return; if (seen_file && viewing_file_method !== "1") file.classList.add('seen'); if (viewing_file_method === "3") { const unsupportedMimeTypes = [ // Audio "audio/3gpp", "audio/ac3", "audio/amr", "audio/flac", "audio/midi", "audio/mp2", "audio/mpegurl", "audio/x-aiff", "audio/x-ms-wax", "audio/x-ms-wma", "audio/x-pn-realaudio", "audio/x-realaudio", "audio/x-scpls", "audio/x-wav", // Video "video/3gpp", "video/3gpp2", "video/dv", "video/mpeg", "video/msvideo", "video/quicktime", "video/vnd.dlna.mpeg-tts", "video/vnd.rn-realvideo", "video/vnd.vivo", "video/x-f4v", "video/x-matroska", "video/x-mng", "video/x-ms-asf", "video/x-ms-wm", "video/x-ms-wmv", "video/x-ms-wvx", "video/x-msvideo", "video/x-sgi-movie", // Image "image/cgm", "image/fits", "image/g3fax", "image/ief", "image/jpm", "image/pcx", "image/pict", "image/x-cmu-raster", "image/x-cmx", "image/x-freehand", "image/x-icon", "image/x-jg", "image/x-portable-anymap", "image/x-portable-bitmap", "image/x-portable-graymap", "image/x-portable-pixmap", "image/x-rgb", "image/x-tga", "image/x-xbitmap", "image/x-xpixmap", "image/x-xwindowdump" ]; const detail = file.dataset.detail; const type = file.dataset.type; const fileDetails = fetch(detail); fileDetails .then(res => res.json()) .then(data => { const { availability, availability_message } = data; if (!unsupportedMimeTypes.includes(type) && (!availability.length || !availability_message.length)) { modal(fileAPIUrl, file); } else { window.open(file.href, "_blank"); } }) .catch(error => { console.error(error); }); } }); //--------------------------------------fetching file data-------------------------------------- const sidebar = document.querySelector('.toolbar'); const albumID = URL.split('/').pop(); // fectch the API to get the file size, type, detail and identifier, allowing us to sort files by size and view them directly in the modal window if the option is selected try { const res = await fetch(`${API}${albumID}`); const { files: filesInfosArrayFromAPI } = await res.json(); const files = document.querySelectorAll('.gallery > .file'); //console.log(filesInfosArrayFromAPI) files.forEach((file, i) => { const { size: fileSize, id: fileID, mime_type: fileType, detail_href: fileDetail } = filesInfosArrayFromAPI[i]; file.setAttribute("data-size", fileSize); file.setAttribute("data-id", fileID); file.setAttribute("data-type", fileType); file.setAttribute("data-detail", `https://pixeldrain.com/api${fileDetail}`); if (viewing_file_method === "2") file.setAttribute("target", "_blank"); if (show_file_size) file.insertAdjacentHTML('beforeend', `${formatFileSize(fileSize)}
`); }); // add button to sidebar sortByFileSize(files, sidebar); if (auto_sort_file) document.querySelector('.sort-button').click(); } catch (error) { console.error(error); } //------------------------------------------CSS Style-------------------------------------------- const pixeldrainStyle = `.sort-button{width:calc(100% - 4px);padding:6px 7px}.sort-icon-container{display:flex}.modal-container,a.file{display:flex!important;flex-direction:column}.sort-button svg{margin-right:2px;filter:invert(.18);pointer-events:none}a.file{position:relative;height:unset!important;justify-content:space-between;padding:0 10px}.seen{border:3px solid #1e90ff}.modal-container{justify-content:center!important;align-items:center!important;position:fixed!important;top:0!important;left:0!important;z-index:9999!important;width:100%!important;height:100%!important;background:rgb(0 0 0 / 90%)!important;animation:.3s ease-in fadeIn!important;backdrop-filter:blur(5px)!important;font-family:system-ui!important}.modal-file-container{position:absolute;width:100%;height:100%;display:flex;flex-direction:column;align-items:center;justify-content:center;-webkit-animation:1s both scale-up-center!important;animation:1s both scale-up-center!important}.modal-file-container audio,.modal-file-container img,.modal-file-container video{max-width:80%;max-height:80%;box-shadow:8px 8px 3px rgba(0 0 0 / .2);border-radius:5px}.modal-file-container audio{max-width:unset!important;max-height:unset!important;width:80%}.download-file-btn{position:relative;z-index:10000;background:#0f0f0f;text-decoration:none;color:#595959;font-size:18px;font-weight:600;padding:2px 15px;box-shadow:0 3px 3px rgba(0,0,0,.6);border:1px solid #131313;border-radius:3px;transition:background .2s;margin-top:15px}.download-file-btn:hover{background:#151515;color:#8c8c8c}.download-file-btn:active{margin-top:2px;background:#0f0f0f}.download-file-btn svg{pointer-events:none;filter:invert(.35)}.download-file-btn:hover svg{filter:invert(42%) sepia(90%) saturate(1352%) hue-rotate(190deg) brightness(85%) contrast(110%)}@keyframes scale-up-center{0%{-webkit-transform:scale(0);transform:scale(0)}100%{-webkit-transform:scale(1);transform:scale(1)}}@keyframes fadeIn{0%{-webkit-opacity:0;opacity:0}100%{-webkit-opacity:1;opacity:1}}`; GM_addStyle(pixeldrainStyle); } })();