Automatically fills TorrentBD upload page with data from Shadow Auto-Uploader
// ==UserScript==
// @name TorrentBD Shadow Upload
// @namespace http://tampermonkey.net/
// @version 1.0
// @description Automatically fills TorrentBD upload page with data from Shadow Auto-Uploader
// @author VORTX
// @license GPL-3.0-or-later
// @match https://www.torrentbd.net/torrents-upload.php*
// @icon https://static.torrentbd.net/bf68ee5a32904d2ca12f3050f9efbf91.png
// @match https://tracker.torrentbd.net/torrents-upload.php*
// @grant GM_xmlhttpRequest
// @connect localhost
// ==/UserScript==
(function() {
'use strict';
console.log("[Shadow Bridge] Script loaded. Checking for data...");
// Create a Toast notification element
const toast = document.createElement("div");
toast.style.position = "fixed";
toast.style.bottom = "20px";
toast.style.right = "20px";
toast.style.backgroundColor = "#1e1e1e";
toast.style.color = "#00ffff";
toast.style.padding = "15px 25px";
toast.style.borderRadius = "5px";
toast.style.boxShadow = "0 0 10px #00ffff";
toast.style.zIndex = "9999";
toast.style.fontFamily = "monospace";
toast.style.transition = "opacity 0.5s";
toast.innerText = "[Shadow] Fetching Data...";
document.body.appendChild(toast);
function showToast(message, isError = false) {
toast.innerText = message;
toast.style.color = isError ? "#ff00ff" : "#00ffff";
toast.style.boxShadow = isError ? "0 0 10px #ff00ff" : "0 0 10px #00ffff";
setTimeout(() => { toast.style.opacity = "0"; }, 5000);
}
function b64toBlob(b64Data, contentType='', sliceSize=512) {
const byteCharacters = atob(b64Data);
const byteArrays = [];
for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
const slice = byteCharacters.slice(offset, offset + sliceSize);
const byteNumbers = new Array(slice.length);
for (let i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
return new Blob(byteArrays, {type: contentType});
}
GM_xmlhttpRequest({
method: "GET",
url: "http://localhost:5000/get_upload_data",
onload: function(response) {
try {
if (response.status === 200) {
const data = JSON.parse(response.responseText);
if (data && data.title && data.description) {
// Find Title Input
const titleInput = document.querySelector('input[name="name"]') || document.querySelector('input#name');
if (titleInput) {
titleInput.value = data.title;
}
// Find Description Textarea
const descInput = document.querySelector('textarea[name="descr"]') || document.querySelector('textarea#descr');
if (descInput) {
descInput.value = data.description;
}
// Auto-fill Torrent File
if (data.torrent_b64 && data.torrent_name) {
const torrentInput = document.querySelector('input[type="file"][name="torrent"]') || document.querySelector('input[type="file"]');
if (torrentInput) {
const blob = b64toBlob(data.torrent_b64, 'application/x-bittorrent');
const file = new File([blob], data.torrent_name, {type: 'application/x-bittorrent'});
const dataTransfer = new DataTransfer();
dataTransfer.items.add(file);
torrentInput.files = dataTransfer.files;
torrentInput.dispatchEvent(new Event('change', { bubbles: true }));
}
}
// Auto-fill Cover Image File
if (data.cover_b64 && data.cover_name) {
const fileInputs = document.querySelectorAll('input[type="file"]');
let coverInput = null;
for (let input of fileInputs) {
if (input.name !== 'torrent' && (input.name.includes('poster') || input.name.includes('image') || input.name.includes('cover') || input.name.includes('file'))) {
coverInput = input;
break;
}
}
// Fallback if we just have two file inputs
if (!coverInput && fileInputs.length >= 2) {
coverInput = fileInputs[1];
}
if (coverInput) {
const blob = b64toBlob(data.cover_b64, 'image/jpeg');
const file = new File([blob], data.cover_name, {type: 'image/jpeg'});
const dataTransfer = new DataTransfer();
dataTransfer.items.add(file);
coverInput.files = dataTransfer.files;
coverInput.dispatchEvent(new Event('change', { bubbles: true }));
}
}
showToast("[Shadow] Data Auto-Filled Successfully!");
} else {
showToast("[Shadow] No valid data found from Python App.", true);
}
} else {
showToast("[Shadow] Failed to fetch data from Python App.", true);
}
} catch (e) {
console.error("[Shadow Bridge] Error parsing data:", e);
showToast("[Shadow] Error parsing JSON data.", true);
}
},
onerror: function(err) {
console.error("[Shadow Bridge] Connection failed:", err);
showToast("[Shadow] Connection to Python app failed.", true);
}
});
})();