208 lines
8.3 KiB
JavaScript
208 lines
8.3 KiB
JavaScript
// ==UserScript==
|
|
// @name AnimeBytes Filelist Improvements
|
|
// @author WeebDataHoarder
|
|
// @version 1.2.1
|
|
// @downloadURL https://git.gammaspectra.live/WeebDataHoarder/userscripts/raw/branch/master/AnimeBytes/ab-filelist.user.js
|
|
// @updateURL https://git.gammaspectra.live/WeebDataHoarder/userscripts/raw/branch/master/AnimeBytes/ab-filelist.user.js
|
|
// @description AnimeBytes Filelist Improvements. Adds full folder path, exact file sizes, fixes path names eating spaces, adds piece information. MIT license
|
|
// @match https://animebytes.tv/torrents.php?*id=*
|
|
// @match https://animebytes.tv/torrents2.php?*id=*
|
|
// @exclude https://animebytes.tv/torrents*groupid=*
|
|
// @icon https://mei.kuudere.pw/jEBHMictkaa.png
|
|
// @grant GM_addStyle
|
|
// @require deps/compat.js?1
|
|
// @require deps/bdecode.js?2
|
|
// @run-at document-end
|
|
// ==/UserScript==
|
|
|
|
let handledTorrentIds = {
|
|
|
|
};
|
|
|
|
const eventHandler = (e) => {
|
|
const tabs = e.target.closest("div.tabs");
|
|
if(tabs === null){ //?????
|
|
return;
|
|
}
|
|
|
|
const fileListElement = tabs.querySelector("div[id$='_filelist']");
|
|
if(fileListElement === null){ //?????
|
|
return;
|
|
}
|
|
|
|
try{
|
|
const torrentId = parseInt(fileListElement.id.match(/^(?<torrentId>[0-9]+)_filelist$/).groups.torrentId);
|
|
|
|
if(torrentId in handledTorrentIds){
|
|
return;
|
|
}
|
|
handledTorrentIds[torrentId] = true;
|
|
|
|
let folderElement = document.getElementById("filelist_" + torrentId + "_foldername");
|
|
if(folderElement !== null){
|
|
return;
|
|
}
|
|
|
|
const downloadLink = document.querySelector("tr.group_torrent a[href^='/torrent/"+torrentId+"/download/']");
|
|
|
|
fetch((new URL(downloadLink.getAttribute("href"), window.location.href)).toString(), {
|
|
method: "GET",
|
|
mode: "same-origin",
|
|
credentials: "omit"
|
|
}).then((response) => response.arrayBuffer().then((buffer) => {
|
|
if(!response.ok){
|
|
return;
|
|
}
|
|
|
|
try{
|
|
const value = bdecode(new Uint8Array(buffer), undefined, undefined);
|
|
|
|
if("info" in value && "name" in value.info){
|
|
let fileList = {};
|
|
|
|
const baseName = value.info.name;
|
|
|
|
const pieceSize = "piece length" in value.info ? value.info["piece length"] : 0;
|
|
const pieceCount = "pieces" in value.info ? value.info.pieces.length / 20 : 0; //SHA1 byte size (160 bits)
|
|
|
|
if("files" in value.info){
|
|
value.info.files.forEach((entry, index) => {
|
|
const path = [baseName].concat(entry.path.slice(0, -1)).join("/");
|
|
const name = entry.path.slice(-1)[0];
|
|
const matchPath = entry.path.slice(0, -1).concat([name]).join("/").replace(/[ \t\r\n]/g, "");
|
|
fileList[path + "/" + name] = {
|
|
index: index,
|
|
path: path,
|
|
name: name,
|
|
match: matchPath,
|
|
length: entry.length,
|
|
};
|
|
});
|
|
}else{
|
|
if(!("length" in value.info)){ // ???
|
|
fileList[baseName] = {
|
|
index: 0,
|
|
path: "",
|
|
name: baseName,
|
|
match: baseName.replace(/[ \t\r\n]/g, ""),
|
|
length: 0,
|
|
};
|
|
}else{
|
|
fileList[baseName] = {
|
|
index: 0,
|
|
path: "",
|
|
name: baseName,
|
|
match: baseName.replace(/[ \t\r\n]/g, ""),
|
|
length: value.info.length,
|
|
};
|
|
}
|
|
}
|
|
|
|
const fileCount = Object.values(fileList).length;
|
|
const fileListTable = document.getElementById("filelist_" + torrentId);
|
|
|
|
const pieceInformation = document.createElement("p");
|
|
pieceInformation.append("Piece Count: " + pieceCount.toLocaleString());
|
|
pieceInformation.append(document.createElement("br"));
|
|
pieceInformation.append("Piece Size: " + ((b) => {
|
|
let i = ~~(Math.log2(b)/10);
|
|
return (b/Math.pow(1024,i)).toFixed(2) + " " + ("KMGTPEZY"[i-1]||"") + "iB"
|
|
})(pieceSize));
|
|
if(fileCount > 1){
|
|
pieceInformation.append(document.createElement("br"));
|
|
pieceInformation.append("File Count: " + fileCount.toLocaleString());
|
|
}
|
|
if("__hash" in value.info){
|
|
value.info.__hash.then((result) => {
|
|
pieceInformation.append(document.createElement("br"));
|
|
pieceInformation.append("Info Hash: " + Array.prototype.map.call(
|
|
new Uint8Array(result),
|
|
n => n.toString(16).padStart(2, "0")
|
|
).join(""))
|
|
});
|
|
}
|
|
fileListTable.insertAdjacentElement("beforebegin", pieceInformation);
|
|
|
|
fileListTable.querySelectorAll("tr").forEach((tableRow, index) => {
|
|
const pathElement = tableRow.querySelector("td");
|
|
|
|
if(tableRow.querySelector("td > strong") !== null){
|
|
//Skip header
|
|
return;
|
|
}
|
|
|
|
const formattedSizeElement = tableRow.querySelector("td:last-of-type");
|
|
|
|
const matchPath = pathElement.textContent.replace(/[ \t\r\n]/g, "");
|
|
|
|
const formattedSize = formattedSizeElement.textContent; //TODO
|
|
let size = "";
|
|
|
|
let path = pathElement.textContent.split("/").splice(0, -1).join("/");
|
|
let name = pathElement.textContent.split("/").splice(-1)[0];
|
|
|
|
for(let [key, entry] of Object.entries(fileList)){
|
|
if(entry.match === matchPath){
|
|
path = entry.path;
|
|
name = entry.name;
|
|
size = entry.length.toLocaleString() + " bytes";
|
|
delete fileList[key];
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
while (pathElement.firstChild) {
|
|
pathElement.firstChild.remove();
|
|
}
|
|
|
|
let pre = document.createElement("code");
|
|
pre.textContent = (path !== "" ? path + "/" : "") + name;
|
|
pathElement.append(pre);
|
|
|
|
if(size !== ""){
|
|
formattedSizeElement.setAttribute("title", size);
|
|
}
|
|
});
|
|
|
|
for(let [key, entry] of Object.entries(fileList)){
|
|
console.log("Unmatched file list for #"+torrentId+" element: " + key);
|
|
console.log(entry);
|
|
}
|
|
}
|
|
}catch (e){
|
|
console.log(e);
|
|
}
|
|
})).catch((e) => {
|
|
|
|
});
|
|
}catch (e){
|
|
console.log(e);
|
|
}
|
|
}
|
|
|
|
GM_addStyle('div.tabs code { font-family: monospace; }');
|
|
|
|
document.querySelectorAll("a[href$='filelist']").forEach((e) => {
|
|
|
|
const match = e.getAttribute("href").match(/^#(?<torrentId>[0-9]+)[_\/]filelist$/);
|
|
if(match !== null){
|
|
const torrentId = parseInt(match.groups.torrentId);
|
|
|
|
if(window.location.hash === ("#" + torrentId + "/filelist")){
|
|
eventHandler({target: e});
|
|
}else{
|
|
e.addEventListener("click", eventHandler, {
|
|
once: true,
|
|
capture: true
|
|
});
|
|
e.addEventListener("mouseover", eventHandler, {
|
|
once: true,
|
|
capture: true
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
});
|