// ==UserScript==
// @name Empornium Deluxe Mode
// @namespace http://tampermonkey.net/
// @version 1.18
// @description Enhances the empornium.me porn torrent website
// @author codingjoe
// @match https://*.empornium.me/*
// @match https://*.empornium.sx/*
// @match https://*.empornium.is/*
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_addStyle
// @grant GM_registerMenuCommand
// @run-at document-idle
// ==/UserScript==
let layout = {
"General": {
"AlwaysHeader": {
type: "checkbox",
text: "Always keep header in view",
defaultValue: false
},
"AutoDismiss": {
type: "checkbox",
text: "Auto-dismiss login timeout notification",
defaultValue: false
},
"JumpToTop": {
type: "checkbox",
text: "Insert 'Jump to Top' link onto bottom-right corner of all pages",
defaultValue: false
},
"PreventNewWindow": {
type: "checkbox",
text: "Prevent single-click links from opening a new window",
defaultValue: false
},
"StripAnonym": {
type: "checkbox",
text: "Strip url anonymizers from links",
defaultValue: false
},
},
"Notifications": {
"CopyClearBottomNotifs": {
type: "checkbox",
text: 'Move "clear" and "clear selected" links onto bottom of matched groups',
defaultValue: false
},
"HideClearAll": {
type: "checkbox",
text: 'Hide "Clear" and "clear all" links to prevent accidental clearing',
defaultValue: false
},
"AutoCheckNotif": {
type: "checkbox",
text: "When the link is clicked, check the torrent's checkbox for manual clearing",
defaultValue: false
},
},
"Torrent Page": {
"AutoOpenFileList": {
type: "checkbox",
text: 'Auto-open filelist',
defaultValue: false
},
"AutoOpenSpoilers": {
type: "checkbox",
text: 'Auto-open hidden text / spoilers',
defaultValue: false
},
"AutoThankUploader": {
type: "checkbox",
text: 'Auto-thank the uploader upon clicking download / freeleech / doubleseed',
defaultValue: false
},
"AutoLoadScaledImages": {
type: "checkbox",
text: 'Automatically load the full res of scaled-down images when possible',
defaultValue: false
}
},
"Torrent Listings": {
"ShowImages": {
type: "checkbox",
text: 'Display hover images inline',
defaultValue: false
},
"ShowHoverTip": {
type: "checkbox",
text: ' Display full hover tip inline',
defaultValue: false,
enabler: "ShowImages"
},
"HideSeeded": {
type: "checkbox",
text: 'Hide currently seeding torrents',
defaultValue: false
},
"HideLeeching": {
type: "checkbox",
text: 'Hide currently leeching torrents',
defaultValue: false
},
"HideGrabbed": {
type: "checkbox",
text: 'Hide previously grabbed torrents [incomplete download]',
defaultValue: false
},
"HideSnatched": {
type: "checkbox",
text: 'Hide previously snatched torrents [finished]',
defaultValue: false
},
},
"Filters": {
"FilterFilesize": {
type: "checkbox",
text: 'Only display torrents in the filesize range:',
defaultValue: false
},
"FilesizeFilterRange": {
type: "range",
defaultValue: { lowerNumber: 0, lowerUnits: "KiB", higherNumber: 999, higherUnits: "TiB" },
enabler: "FilterFilesize", // enabler indicates which checkbox must be checked to enable the field
units: ["KiB", "MiB", "GiB", "TiB"]
},
"FilterTags": {
type: "checkbox",
text: 'Torrents displayed to me must <u>not</u> have any of the following tags (black list):',
defaultValue: false
},
"TagListing": {
type: "textarea",
text: '(comma-separated list)',
defaultValue: "bbc, big.black.cock, bbw, fat, obese, hairy, gay, trans, tranny, transsexual, scat, feces, poop, puke, vomit, censored",
title: "black list",
enabler: "FilterTags" // enabler indicates which checkbox must be checked to enable the field
},
"OnlyShowTheseTags": {
type: "checkbox",
text: 'Torrents displayed to me <b>must have</b> at least one of the following tags:',
defaultValue: false
},
"OnlyShowTagListing": {
type: "textarea",
text: '(comma-separated list)',
defaultValue: "swallowed.com, evilangel.com, amourangels.com, met-art.com, legalporno.com, mplstudios.com, femjoy.com, sexart.com, ftvgirls.com, teenpornstorage.com, domai.com, analteenangels.com, showybeauty.com, justteensite.com, facefucking.com, teenfidelity.com, chaturbate.com, myfreecams.com, twistys.com, atkgalleria.com, iameighteen.com",
title: "must-have list",
enabler: "OnlyShowTheseTags" // enabler indicates which checkbox must be checked to enable the field
},
},
"Bonus": {
"ShowRatioGoals": {
type: "checkbox",
text: 'Display ratio goals table on the Bonus Shop page (experimental)',
defaultValue: false
},
}
};
let customContentStyle = `
.emp_modal_content {
display: inline !important;
width: 900px !important;
height: auto !important;
background-color: #000525 !important;
margin-top: 0% !important;
margin-left: -450px !important;
position: absolute !important;
top: 0% !important;
left: 50% !important;
text-align: center !important;
overflow-y: auto !important;
color: #2C8466 !important;
}
`;
let accordionStyle = {
backgroundColor: "#0E2D4A",
color: "white",
cursor: "pointer",
padding: "18px",
width: "100%",
border: "none",
textAlign: "center",
outline: "none",
fontSize: "15px",
transition: "0.4s",
borderRadius: "5px"
};
let panelStyle = {
padding: "0 18px",
display: "none",
overflow: "hidden",
textAlign: "left",
backgroundColor: "#000015",
fontSize: "10pt"
};
let textareaStyle = {
width: "870px",
height: "65px",
backgroundColor: "#0E2D4A",
color: "silver",
marginTop: "10px"
};
Element.prototype.props = function(json) {
return Object.assign(this, json);
};
HTMLDocument.prototype.new = function(tagName) {
return document.createElement(tagName);
};
Element.prototype.appendTo = function(element) {
element.appendChild(this);
return this;
};
Element.prototype.setStyle = function(styler) {
Object.assign(this.style, styler);
return this;
}
let GM_config = {};
class ConfigDialog {
constructor(configId, headerText) {
this.configId = configId;
this.headerText = headerText;
// create modal dialog background
this.modal = document.body.appendChild(document.createElement("div")).setStyle({
display: "none",
position: "fixed",
left: 0,
top: 0,
width: "100%",
height: "100%",
overflow: "auto",
backgroundColor: "rgba(0,0,0,0.7)",
zIndex: 9999
});
// create a space for content inside the modal
this.content = this.modal.appendChild(Object.assign(document.createElement("div"), { className: "emp_modal_content" }));
GM_addStyle(`
.emp_modal_content {
display: inline;
width: 250;
height: 250;
background-color: white;
margin-top: -125px;
margin-left: -125px;
position: absolute;
top: 50%;
left: 50%;
text-align: center;
}
`);
let self = this;
// handle modal close on click
window.addEventListener("click", function(e) {
if (e.target === self.modal) {
self.Close();
}
});
// retrieve settings
this.savedValues = GM_getValue("EmporniumEnhancementsConfig")? JSON.parse(GM_getValue("EmporniumEnhancementsConfig")): null;
if (!this.savedValues) {
// load default settings
this.savedValues = this.GatherDefaultValues();
}
Object.keys(layout).forEach(header => {
Object.keys(layout[header]).forEach(id => {
if (id === "FilesizeFilterRange") {
if (!this.savedValues[id]) {
if (GM_getValue("fileSizeRange")) {
this.savedValues[id] = JSON.parse(GM_getValue("fileSizeRange"));
} else {
this.savedValues[id] = layout.Filters[id].defaultValue;
}
}
} else {
// auto-detect new settings
if (!Object.keys(this.savedValues).includes(id)) {
let defaultValue = null;
Object.keys(layout).forEach(header => {
if (Object.keys(layout[header]).includes(id)) {
defaultValue = layout[header][id].defaultValue;
}
});
this.savedValues[id] = defaultValue;
}
}
});
});
GM_setValue("EmporniumEnhancementsConfig", JSON.stringify(this.savedValues));
GM_config = this.savedValues;
this.Customize_UI(self);
}
Open() {
this.modal.style.display = "block";
document.body.style.overflow = "hidden";
}
Close() {
this.modal.style.display = "none";
document.body.style.overflow = "";
this.ResetUI();
}
ResetUI() {
// collapse all accordion headers
document.querySelectorAll(".configHeader").forEach(r => {
if (r.classList.contains("active_header")) {
r.classList.remove("active_header");
r.style.backgroundColor = "#0E2D4A";
}
});
// hide all panels with a list of settings
document.querySelectorAll(".configPanel").forEach(r => {
r.style.display = "none";
});
// reset fields to the stored values
document.querySelectorAll(`[id^='${this.configId}_var_']`).forEach(r => {
switch (r.type || r.getAttribute("type")) {
case "checkbox":
r.checked = this.savedValues[r.id.replace(`${this.configId}_var_`,"")];
// determine disabled state of fields the checkbox governs
document.querySelectorAll(`[data-enabler='${r.id.replace(`${this.configId}_var_`, "")}']`).forEach(d => {
//d.disabled = !this.checked;
if (this.checked) {
d.disabled = true;
} else {
if (d.hasAttribute("disabled")) {
d.removeAttribute("disabled");
}
}
});
break;
case "textarea":
case "text":
case "number":
case "date":
case "select":
r.value = this.savedValues[r.id.replace(`${this.configId}_var_`,"")];
break;
case "range":
r.querySelectorAll("input,select").forEach(element => element.value = this.savedValues[r.id.replace(`${this.configId}_var_`,"")][element.id]);
break;
default:
console.log(`ResetUI implement '${r.type || r.getAttribute("type")}'`);
}
});
}
GatherFieldValues() {
let self = this;
this.savedValues = {};
// gather setting values from input fields
document.querySelectorAll(`[id^='${this.configId}_var_']`).forEach(r => {
switch (r.type || r.getAttribute("type")) {
case "checkbox":
this.savedValues[r.id.replace(`${this.configId}_var_`,"")] = r.checked;
break;
case "textarea":
case "text":
case "number":
case "date":
case "select":
this.savedValues[r.id.replace(`${this.configId}_var_`,"")] = r.value;
break;
case "range":
let rangeId = r.id.replace(`${this.configId}_var_`,"");
this.savedValues[rangeId] = {};
r.querySelectorAll("input,select").forEach(element => this.savedValues[rangeId][element.id] = element.value);
break;
default:
console.log(`GatherFieldValues implement '${r.type || r.getAttribute("type")}'`);
}
});
}
GatherDefaultValues() {
let defaultValues = {};
// gather a list of defaults from the layout
Object.keys(layout).forEach(header => {
Object.keys(layout[header]).forEach(id => {
let setting = layout[header][id];
defaultValues[id] = setting.defaultValue;
});
});
return defaultValues;
}
ResetFieldsToDefaults() {
let defaultValues = this.GatherDefaultValues();
// reset fields to their default values
document.querySelectorAll(`[id^='${this.configId}_var_']`).forEach(r => {
switch (r.type || r.getAttribute("type")) {
case "checkbox":
r.checked = defaultValues[r.id.replace(`${this.configId}_var_`,"")];
break;
case "textarea":
case "text":
case "number":
case "date":
case "select":
r.value = defaultValues[r.id.replace(`${this.configId}_var_`,"")];
break;
case "range":
let rangeId = r.id.replace(`${this.configId}_var_`,"");
let rangeValues = {};
Object.keys(layout).forEach(k => {
if (Object.keys(layout[k]).includes(rangeId)) {
rangeValues = layout[k][rangeId].defaultValue;
}
});
r.querySelectorAll("input,select").forEach(element => element.value = rangeValues[element.id]);
break;
default:
console.log(`ResetFieldsToDefaults implement '${r.type || r.getAttribute("type")}'`);
}
});
document.querySelectorAll("[data-enabler]").forEach(r => r.disabled = true);
}
Save() {
this.GatherFieldValues();
// store to userscript
GM_setValue("EmporniumEnhancementsConfig", JSON.stringify(this.savedValues));
GM_config = this.savedValues;
this.Close();
location.reload();
}
RenderFields(self, header) {
// generate settings panel
let panel = this.content.appendChild(document.createElement("div"));
panel.classList.add("configPanel");
panel.setStyle(panelStyle);
Object.keys(layout[header]).forEach(id => {
let setting = layout[header][id];
let fieldContainer = document.createElement("div");
let label = null;
let hr = null;
let enabler = null;
if (setting.type !== "range") {
label = fieldContainer.appendChild(Object.assign(document.createElement("label"), { innerHTML: setting.text }));
label.setAttribute("for", `${this.configId}_var_${id}`);
label.style.marginRight = "5px";
}
switch (setting.type) {
case "checkbox":
let chk = fieldContainer.appendChild(Object.assign(document.createElement("input"), { id: `${this.configId}_var_${id}`, type: setting.type }));
chk.checked = this.savedValues[id];
if (setting.enabler !== undefined) {
chk.setAttribute("data-enabler", setting.enabler);
enabler = panel.querySelector(`#${this.configId}_var_${setting.enabler}`);
chk.disabled = !enabler.checked;
}
break;
case "text":
let textbox = fieldContainer.appendChild(Object.assign(document.createElement("input"), { id: `${this.configId}_var_${id}`, type: setting.type, value: this.savedValues[id] }));
break;
case "textarea":
let textarea = fieldContainer.appendChild(Object.assign(document.createElement("textarea"), { id: `${this.configId}_var_${id}`, value: this.savedValues[id] })).setStyle(textareaStyle);
hr = fieldContainer.appendChild(document.createElement("hr"));
hr.style = "margin-top: 5px; margin-bottom: 10px";
if (setting.enabler !== undefined) {
textarea.setAttribute("data-enabler", setting.enabler);
enabler = panel.querySelector(`#${this.configId}_var_${setting.enabler}`);
textarea.disabled = !enabler.checked;
}
break;
case "range":
let rangeFields = [];
let lowerUnits = null;
let higherUnits = null;
let lowerNumber = fieldContainer.appendChild(document.createElement("input")).setStyle({ width: "50px" });
Object.assign(lowerNumber, {
id: "lowerNumber",
type: "number",
min: 0,
max: 999,
value: this.savedValues[id].lowerNumber
});
rangeFields.push(lowerNumber);
if (setting.units) {
lowerUnits = fieldContainer.appendChild(Object.assign(document.createElement("select"), { id: "lowerUnits" }));
rangeFields.push(lowerUnits);
}
fieldContainer.appendChild(Object.assign(document.createElement("label"), { innerText: " to " }));
let higherNumber = fieldContainer.appendChild(document.createElement("input")).setStyle({ width: "50px" });
Object.assign(higherNumber, {
id: "higherNumber",
type: "number",
min: 0,
max: 999,
value: this.savedValues[id].higherNumber
});
rangeFields.push(higherNumber);
if (setting.units) {
higherUnits = fieldContainer.appendChild(Object.assign(document.createElement("select"), { id: "higherUnits" }));
rangeFields.push(higherUnits);
setting.units.forEach(u => {
lowerUnits.appendChild(Object.assign(document.createElement("option"), { text: u, value: u }));
higherUnits.appendChild(Object.assign(document.createElement("option"), { text: u, value: u }));
});
lowerUnits.value = this.savedValues[id].lowerUnits;
higherUnits.value = this.savedValues[id].higherUnits;
}
rangeFields.forEach(r => r.setStyle({ backgroundColor: "#0E2D4A", color: "silver" }));
if (setting.enabler !== undefined) {
enabler = panel.querySelector(`#${this.configId}_var_${setting.enabler}`);
rangeFields.forEach(r => {
r.setAttribute("data-enabler", setting.enabler);
r.disabled = !enabler.checked;
});
}
hr = fieldContainer.appendChild(document.createElement("hr"));
hr.style = "margin-top: 5px; margin-bottom: 10px";
fieldContainer.id = `${this.configId}_var_${id}`;
fieldContainer.setAttribute("type", setting.type);
break;
default:
fieldContainer = Object.assign(document.createElement("div"), { innerText: setting.text });
break;
}
// tie checkox to trigger the disabled state of the form elements it governs
if (enabler) {
enabler.addEventListener("change", function(e) {
document.querySelectorAll(`[data-enabler='${this.id.replace(self.configId + "_var_", "")}']`).forEach(r => r.disabled = !this.checked);
});
}
panel.appendChild(fieldContainer);
});
}
RenderAccordion(self) {
Object.keys(layout).forEach(header => {
// generate accordion
let category = this.content.appendChild(Object.assign(document.createElement("button"), { innerText: header }));
category.classList.add("configHeader");
category.setStyle(accordionStyle);
// activate accordion header on mouse enter
category.addEventListener("mouseenter", function(e) {
this.style.backgroundColor = "#133C5F";
});
category.addEventListener("mouseleave", function(e) {
// deactivate accordion header on mouse leave
if (!this.classList.contains("active_header")) {
this.style.backgroundColor = "#0E2D4A";
}
});
category.addEventListener("click", function(e) {
// toggle accordion active state
if (this.classList.contains("active_header")) {
this.classList.remove("active_header");
} else {
this.classList.add("active_header");
}
let settingsPanel = this.nextElementSibling;
if (settingsPanel.style.display === "block") {
settingsPanel.style.display = "none";
} else {
settingsPanel.style.display = "block";
}
});
// render fields
this.RenderFields(self, header);
});
}
Customize_UI(self) {
// customize content box
GM_addStyle(customContentStyle)
// create UI elements
// header text
let headerDiv = this.content.appendChild(document.createElement("div")).setStyle({ fontSize: "20pt" });
let lblTitle = headerDiv.appendChild(Object.assign(document.createElement("label"), { innerHTML: this.headerText }));
this.RenderAccordion(self);
// footer to contain buttons on the right
let footerDiv = this.content.appendChild(document.createElement("div")).setStyle({ width: "100%", textAlign: "right", marginTop: "10px" });
// create save button
let btnSave = footerDiv.appendChild(Object.assign(document.createElement("input"), { type: "button", value: "Save" })).setStyle({ width: "50px" });
btnSave.addEventListener("click", function(e) {
self.Save();
});
// create reset to defaults button
let btnReset = footerDiv.appendChild(Object.assign(document.createElement("input"), { type: "button", value: "Reset to defaults" })).setStyle({ width: "115px" });
btnReset.addEventListener("click", function(e) {
self.ResetFieldsToDefaults();
});
}
}
function myRound(x, places) {
let trunc = Math.pow(10, places);
return Math.round(x * trunc) / trunc;
}
function Insert_JumpToTop() {
if (GM_config.JumpToTop) {
// create a div fixed in the bottom-right corner
let jumpDiv = document.createElement("div");
jumpDiv.setStyle({
position: "fixed",
bottom: "5px",
right: "5px",
textAlign: "right"
});
// create the 'Jump to Top' link
let anchor = document.createElement("a");
anchor.innerText = "Jump to Top";
anchor.href = "javascript:window.scrollTo(0, 0)";
// append the link to the corner div
jumpDiv.appendChild(anchor);
// append the entire element to the body of the page
document.body.appendChild(jumpDiv);
}
}
function Affix_Header() {
if (GM_config.AlwaysHeader) {
if (document.querySelectorAll("#header").length > 0) {
// affix the header into position
document.querySelector("#header").style.cssText = "position: fixed !important; top: 0px; left: 0px;";
// shift the contents down to account for missing space
document.querySelector("#content").style.cssText = "margin-top:120px;";
}
}
}
function Strip_Anon(links) {
if (GM_config.StripAnonym) {
// list of url anonymizers to remove
let anonymizers = [ "http://anonym.to/?", "http://anon.now.im/?", "https://anonym.es/?", "http://anonym.es/?" ];
// loop over each link
links.forEach(link => {
// loop thru the list of anonymizers
anonymizers.forEach(anonymizer => {
// if link contains current anonymizer
if (link.href.indexOf(anonymizer) >= 0) {
console.log(`Removing url anonymizer '${anonymizer}' from link '${link.href}'`);
// replace it with empty string
link.href = link.href.replace(anonymizer, "");
}
});
});
}
}
function Prevent_NewWindow(links) {
if (GM_config.PreventNewWindow) {
// loop over each link
links.forEach(link => {
// if a new window target has been set for current link
if (link.target.length > 0) {
// remove its target
link.target = '';
}
});
}
}
function AutoOpen_Spoilers(links) {
if (GM_config.AutoOpenSpoilers) {
console.log("AutoOpenSpoilers");
// find all spoiler links
links.filter(r => r.innerHTML === "Show").forEach(link => {
// click to unhide
link.click();
});
}
}
function AutoDismiss_LoginTimeout() {
if (GM_config.AutoDismiss) {
if (document.querySelectorAll("#flashClose").length > 0) {
document.querySelector("#flashClose").click()
}
}
}
function RedirectTo_LoginScreen(links) {
if (links.filter(r => r.innerHTML === "Login").length > 0) {
window.location.href += "login";
}
}
function SetFocus_LoginForm() {
document.querySelector("input[name=username]").focus();
}
function Show_RatioGoals() {
if (GM_config.ShowRatioGoals) {
var stats = document.querySelectorAll(".stat");
var units = [ "KiB", "MiB", "GiB", "TiB" ];
var ratio = parseFloat(stats[5].innerText);
var down = stats[3].innerText;
var up = stats[1].innerText;
var upUnitsIdx = units.indexOf(up.substring(1 + up.indexOf(" ")));
var downUnitsIdx = units.indexOf(down.substring(1 + down.indexOf(" ")));
var unitsDiff = parseInt(Math.round(upUnitsIdx - downUnitsIdx));
var displayUnits = units[downUnitsIdx];
up = up.replace(/,/g, "");
up = parseFloat(up.substring(0, up.indexOf(" ")));
down = down.replace(/,/g, "");
down = parseFloat(down.substring(0, down.indexOf(" ")));
// convert totals to same units
if (unitsDiff < 0) {
down *= Math.pow(1024, -unitsDiff);
displayUnits = units[upUnitsIdx];
} else if (unitsDiff > 0) {
up *= Math.pow(1024, unitsDiff);
}
var diff = down / 100.0;
var currAmount = Math.abs((ratio + 0.01) * down - up);
let strHtml = "<table style=\"text-align:center !important;margin: 0px auto; width:50%;\">\
<tbody>\
<tr>\
<td style=\"width:90px;text-align:center;\">U/L differential</td>\
<td style=\"width:90px;text-align:center;\"> for ratio </td>\
<td style=\"width:90px;text-align:center;\"> Amount to U/L </td>\
</tr>";
for (let i = 1; i <= 10; i++) {
var currRatio = i/100.0 + ratio;
// alternate background color
var style = "";
if (i % 2 != 0) {
style = " style=\"background-color:#222222 !important;\"";
}
strHtml += "<tr" + style + "><td style=\"text-align:center;\"> +" + (i == 1 ? myRound(currAmount, 3) : myRound(diff, 3)) + " " + displayUnits + " </td><td style=\"text-align:center;\"> " + myRound(currRatio, 3) + " </td><td style=\"text-align:center;\"> " + myRound(currAmount, 3) + " " + displayUnits + " </td></tr>";
currAmount += diff;
}
strHtml += "</tbody></table>";
var content = document.querySelector("#content");
content.innerHTML = strHtml + content.innerHTML;
}
}
function Hide_Seeded(torrents) {
if (GM_config.HideSeeded) {
torrents.filter(r => r.querySelectorAll(".icon_disk_seed").length > 0).forEach(itemRow => { itemRow.style = "display:none"; });
}
}
function Hide_Grabbed(torrents) {
if (GM_config.HideGrabbed) {
torrents.filter(r => r.querySelectorAll(".icon_disk_grabbed").length > 0).forEach(itemRow => { itemRow.style = "display:none"; });
}
}
function Hide_Snatched(torrents) {
if (GM_config.HideSnatched) {
torrents.filter(r => r.querySelectorAll(".icon_disk_snatched").length > 0).forEach(itemRow => { itemRow.style = "display:none"; });
}
}
function Hide_Leeching(torrents) {
if (GM_config.HideLeeching) {
torrents.filter(r => r.querySelectorAll(".icon_disk_leech").length > 0).forEach(itemRow => { itemRow.style = "display:none"; });
}
}
function BlackList_TheseTags(torrents) {
if (GM_config.FilterTags) {
// grab the filters from the settings
let filters = GM_config.TagListing.replace(/[\n\r\s]/g, "").split(',');
let intersect = function(A,B) { return A.filter(r => B.indexOf(r) >= 0) }
let intersects = function(A,B) { return intersect(A,B).length > 0 }
// loop over each torrent
torrents.filter(r => r.style.display !== "none").forEach(itemRow => {
// grab the current torrent's list of tags
let tags = itemRow.querySelector(".tags").innerText.split(" ");
// if the filter keywords and tags have items in common
if (intersects(filters,tags)) {
// hide this torrent row
itemRow.style.display = "none";
let torrentInfo = Array.from(itemRow.querySelectorAll("a")).filter(r => /\/torrents\.php\?id\=\d+$/.test(r.href))[0]
console.log(`Blacklisted found: "${intersect(filters,tags).join(",")}", therefore the torrent "${torrentInfo.href} - ${torrentInfo.innerText}" was hidden`);
}
});
}
}
function Display_ImagesInline(torrents) {
if (GM_config.ShowImages) {
// loop over each torrent
torrents.forEach(itemRow => {
// if current torrent row contains a hover script and a cats_col class of element exists within it
if (itemRow.querySelectorAll("script").length > 0 && itemRow.querySelectorAll("[class*=cats_col]").length > 0) {
// extract the image-generating html from the hover script
let strHtml = itemRow.querySelector("script").innerHTML.replace(/[\[\]\{\}\(\)\\\|]/g, "");
let start = strHtml.indexOf("\"")+1;
let end = strHtml.lastIndexOf("\"");
strHtml = strHtml.substring(start, end);
// create a div within which to place the image
let div = document.createElement("div");
// hide the cats_col's child elements which contain a definite title to make room for the image
Array.from(itemRow.querySelector("[class*=cats_col]").childNodes).filter(r => r.title !== undefined).forEach(cat => { cat.style.display = "none"; });
// add the html to generate the image to the div
div.innerHTML = strHtml;
// display the image in the torrent row
if (GM_config.ShowHoverTip) {
itemRow.querySelector("[class*=cats_col]").appendChild(div);
} else {
itemRow.querySelector("[class*=cats_col]").appendChild(div.querySelector("img"));
}
}
});
}
}
function Hide_ClearAll(links) {
if (GM_config.HideClearAll) {
// hide "clear all" and "Clear"
links.filter(r => r.innerHTML === "(clear all)" || r.innerHTML === "Clear").forEach(link => { link.style.display = "none"; });
}
}
function AutoCheck_ClickedTorrent(torrents) {
if (GM_config.AutoCheckNotif) {
// loop over entire torrent list
torrents.forEach(itemRow => {
// filter-out links on current torrent that do not contain "/torrents.php?id"
Array.from(itemRow.querySelectorAll("a")).filter(r => r.href.indexOf("/torrents.php?id") > -1).forEach(link => {
link.addEventListener("mousedown", function (e) {
// activate checkbox of current torrent if notification link was clicked
itemRow.querySelector("input[type=checkbox]").checked = true;
});
});
});
}
}
function Move_ClearToGroupBottom() {
if (GM_config.CopyClearBottomNotifs) {
// look for the torrent_table class of elements
document.querySelectorAll(".torrent_table").forEach(t => {
// find the current table's previous sibling's previous sibling
let ps = t.previousSibling.previousSibling;
// clone the element
let c = ps.cloneNode(true);
// insert at the bottom
t.parentNode.insertBefore(c, t.nextSibling);
ps.innerHTML = ps.innerHTML.toString().match(/(\w+\s){4}/gm);
});
}
}
function Filter_Filesizes(torrents) {
if (GM_config.FilterFilesize) {
let units = [ "KiB", "MiB", "GiB", "TiB" ];
let filesizeRange = GM_config.FilesizeFilterRange;
let torrentInfo = null;
let colhead = document.querySelector(".colhead");
let torrentHeader = null;
if (colhead) {
torrentHeader = Array.from(colhead.querySelectorAll("td")).map(r => r.innerHTML.startsWith("<img")? r.innerHTML.match(/title\=\"([^\"]+)\"/)[1]: r.innerText);
// loop over each torrent
torrents.filter(r => r.style.display !== "none").forEach(itemRow => {
let sizeCell = itemRow.querySelectorAll("td")[torrentHeader.indexOf("Size")];
// retrieve filesize of current torrent
let currSize = sizeCell.innerText.split(" ");
currSize[0] = currSize[0].replace(",","");
// hide row if units of current row are less than units of min range
if (units.indexOf(currSize[1]) < units.indexOf(filesizeRange.lowerUnits)) {
itemRow.style.display = "none";
torrentInfo = Array.from(itemRow.querySelectorAll("a")).filter(r => /\/torrents\.php\?id\=\d+$/.test(r.href))[0]
console.log(`${currSize.join("")} < ${filesizeRange.lowerNumber}${filesizeRange.lowerUnits}; hide the torrent '${torrentInfo.href} - ${torrentInfo.innerText}'`);
} else if (currSize[1] === filesizeRange.lowerUnits) {
// hide row if units match and filesize is less than min range
if (parseFloat(currSize[0]) < parseInt(filesizeRange.lowerNumber)) {
itemRow.style.display = "none";
torrentInfo = Array.from(itemRow.querySelectorAll("a")).filter(r => /\/torrents\.php\?id\=\d+$/.test(r.href))[0]
console.log(`${currSize.join("")} < ${filesizeRange.lowerNumber}${filesizeRange.lowerUnits}; hide the torrent '${torrentInfo.href} - ${torrentInfo.innerText}'`);
}
}
// hide row if units of current row are greater than units of max range
if (units.indexOf(currSize[1]) > units.indexOf(filesizeRange.higherUnits)) {
itemRow.style.display = "none";
torrentInfo = Array.from(itemRow.querySelectorAll("a")).filter(r => /\/torrents\.php\?id\=\d+$/.test(r.href))[0]
console.log(`${currSize.join("")} > ${filesizeRange.higherNumber}${filesizeRange.higherUnits}; hide the torrent '${torrentInfo.href} - ${torrentInfo.innerText}'`);
} else if (currSize[1] === filesizeRange.higherUnits) {
// hide row if units match and filesize is greater than max range
if (parseFloat(currSize[0]) > parseInt(filesizeRange.higherNumber)) {
itemRow.style.display = "none";
torrentInfo = Array.from(itemRow.querySelectorAll("a")).filter(r => /\/torrents\.php\?id\=\d+$/.test(r.href))[0]
console.log(`${currSize.join("")} > ${filesizeRange.higherNumber}${filesizeRange.higherUnits}; hide the torrent '${torrentInfo.href} - ${torrentInfo.innerText}'`);
}
}
});
} else {
console.log("Unable to filter filesizes; could not find torrent listing column header.");
}
}
}
function Draw_MenuItem(callback) {
if (document.querySelector(".username") != null) {
// config icon - wrench & screwdriver depicted
let icon = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA\
u0lEQVQ4jZ2SMQ4CMQwERyiICqEr+EGgRBelpkvLI3kDD+IBdDQUFKbJIcdyTqezlGazu7\
ZXBlM55+1ajFLyYS2mQanv4hFDCNP/rKNUoid+NAZql5MxFODriMtkEGPcNV2BsxIL8O6J\
vfVE7fd/w7C/LhFjOosxTEvETTnTjK7YO4hKDM40o+bZEO0qnwrZbNKSHF4OZoNtK6V4VC\
QtnkoAUYZuZwE2vRHVdbqXeO90ttgTuEEnRA+cw36EkV9UhABsAgAAAABJRU5ErkJggg==";
// find the user nav element
let navbar = document.querySelector(".username").parentNode.querySelector("ul");
// clone a list item layout
let configNode = navbar.querySelector("li").cloneNode(true);
// wire-up the config element
configNode.id = "deluxe_config";
configNode.innerHTML = "";
let anchor = document.new("a").appendTo(configNode);
anchor.title = "Empornium Deluxe Mode Configuration";
anchor.innerHTML = '<img src="' + icon + '" style="filter:invert(100%);"/> Deluxe Mode Config';
anchor.href = "javascript:void(0)";
anchor.addEventListener("click", function (e) {
callback();
});
// display config link as first item in the user nav
navbar.insertBefore(configNode, navbar.firstChild);
}
}
function AutoThank_Uploader() {
if (GM_config.AutoThankUploader) {
// .blueButton => Download
// .greenButton => Freeleech
// .orangeButton => Doubleseed
// look for the download / freeleech / doubleseed buttons
Array.from(document.querySelectorAll(".blueButton,.greenButton,.orangeButton")).forEach(btn => {
// wire-up event to auto-click thanks upon downloading
btn.addEventListener("click", function (e) {
window.setTimeout(function () {
// if thanks button not disabled
if (!document.querySelector("#thanksbutton").disabled) {
// invoke it
document.querySelector("#thanksbutton").click();
}
// wait 500ms so as not to interrupt download request
}, 500);
});
});
}
}
function AutoOpen_FileList(links) {
if (GM_config.AutoOpenFileList) {
links.filter(r => r.innerHTML === "(View Filelist)")[0].click();
}
}
function MustHave_TheseTags(torrents) {
if (GM_config.OnlyShowTheseTags) {
// grab the filters from the settings
let filters = GM_config.OnlyShowTagListing.replace(/[\n\r\s]/g, "").split(',');
let intersect = function(A,B) { return A.filter(r => B.indexOf(r) >= 0) }
let intersects = function(A,B) { return intersect(A,B).length > 0 }
// loop over each torrent
torrents.filter(r => r.style.display !== "none").forEach(itemRow => {
// grab the current torrent's list of tags
let tags = itemRow.querySelector(".tags").innerText.split(" ");
// if the filter keywords and tags do not have items in common
if (!intersects(filters,tags)) {
// hide this torrent row
itemRow.style = "display:none";
let torrentInfo = Array.from(itemRow.querySelectorAll("a")).filter(r => /\/torrents\.php\?id\=\d+$/.test(r.href))[0]
console.log(`Not found on must-have list: "${tags.filter(r => r !== "").join(",")}", therefore the torrent "${torrentInfo.href} - ${torrentInfo.innerText}" was hidden`);
}
});
}
}
function AutoLoad_ScaledImages() {
if (GM_config.AutoLoadScaledImages) {
Array.from(document.querySelectorAll(".scale_image")).forEach((r, idx) => {
setTimeout(function() {
// detect thumbnails and medium scaled images
let newsrc = r.src.replace(".th","").replace(".md","");
r.src = newsrc;
r.parentNode.href = newsrc;
}, idx * 3000); // put a delay of 3sec between each full-res image request
});
}
}
// main
(function() {
'use strict';
let headerText = "Empornium Deluxe Mode Config";
let config = new ConfigDialog("EmporniumConfig", headerText);
GM_registerMenuCommand(headerText, function() {
config.Open();
});
AutoDismiss_LoginTimeout();
Draw_MenuItem(function() {
config.Open();
});
let links = Array.from(document.querySelectorAll("a"));
let torrents = Array.from(document.querySelectorAll(".torrent"));
// page match rules
if (/empornium\.(me|is|sx)\/?$/.test(window.location.href)) {
RedirectTo_LoginScreen(links);
} else if (/empornium\.(me|is|sx)\/login$/.test(window.location.href)) {
SetFocus_LoginForm();
} else {
// occurs on all authenticated pages
Affix_Header();
Strip_Anon(links);
Prevent_NewWindow(links);
Insert_JumpToTop();
if (/torrents\.php.+action=notify/.test(window.location.href)) {
// notifications page
Hide_ClearAll(links);
Move_ClearToGroupBottom();
AutoCheck_ClickedTorrent(torrents);
}
if (/(top10|user)\.php/.test(window.location.href) || (/torrents\.php/.test(window.location.href) && !/(\?|&)id=/.test(window.location.href))) {
// torrents / top10 / user - lists of torrents
BlackList_TheseTags(torrents);
Filter_Filesizes(torrents);
MustHave_TheseTags(torrents);
Hide_Seeded(torrents);
Hide_Grabbed(torrents);
Hide_Snatched(torrents);
Hide_Leeching(torrents);
Display_ImagesInline(torrents);
} else if (/torrents\.php\?id=\d+/.test(window.location.href)) {
console.log("single torrent page");
// single torrent landing page
AutoOpen_Spoilers(links);
AutoOpen_FileList(links);
AutoThank_Uploader();
AutoLoad_ScaledImages();
} else if (/bonus\.php/.test(window.location.href)) {
// bonus page
Show_RatioGoals();
}
}
})();