Empornium Deluxe Mode

Enhances the empornium.me porn torrent website

À partir de 2019-07-09. Voir la dernière version.

  1. // ==UserScript==
  2. // @name Empornium Deluxe Mode
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.13
  5. // @description Enhances the empornium.me porn torrent website
  6. // @author codingjoe
  7. // @match https://*.empornium.me/*
  8. // @include /empornium\.me/
  9. // @require https://openuserjs.org/src/libs/sizzle/GM_config.js
  10. // @grant GM_getValue
  11. // @grant GM_setValue
  12. // @grant GM_addStyle
  13. // @grant GM_registerMenuCommand
  14. // @run-at document-idle
  15. // ==/UserScript==
  16.  
  17. // returns a list of elements contained in both lists (i.e. set intersection)
  18. Array.prototype.intersect = function (lst) {
  19. return this.filter(r => lst.indexOf(r) >= 0);
  20. };
  21.  
  22. // determines whether or not there exists an intersection between the two lists
  23. // tests for one or more elements in common
  24. Array.prototype.intersects = function (lst) {
  25. return this.intersect(lst).length > 0;
  26. };
  27.  
  28. // returns a list of elements unique to both lists
  29. Array.prototype.union = function(lst) {
  30. let u = [];
  31. this.concat(lst).forEach(r => { if (!u.includes(r)) { u.push(r); } });
  32. return u;
  33. };
  34.  
  35. Element.prototype.props = function(json) {
  36. return Object.assign(this, json);
  37. };
  38.  
  39. HTMLDocument.prototype.new = function(tagName) {
  40. return document.createElement(tagName);
  41. };
  42.  
  43. Element.prototype.appendTo = function(element) {
  44. element.appendChild(this);
  45. return this;
  46. };
  47.  
  48. function RenderAccordion(layout, wrapper) {
  49. let div = document.createElement("div");
  50.  
  51. // display the fields under the designated accordion label
  52. Object.keys(layout).forEach(header => {
  53. // create the category header on the accordion
  54. let category = document.new("button").props({ className: "accordion", innerText: header }).appendTo(div);
  55.  
  56. // wire-up accordion node to reveal its contents
  57. category.addEventListener("click", function() {
  58. this.classList.toggle("active");
  59. let panel = this.nextElementSibling;
  60. if (panel.style.display === "block") {
  61. panel.style.display = "none";
  62. } else {
  63. panel.style.display = "block";
  64. }
  65. });
  66.  
  67. // create the content panel of this accordion
  68. let settingsList = document.new("div").props({ className: "panel" }).appendTo(div);
  69.  
  70. // render the settings within the content panel
  71. layout[header].forEach(setting => {
  72. settingsList.appendChild(wrapper.querySelector("[id$=" + setting + "_var]"));
  73. });
  74. });
  75.  
  76. return div;
  77. }
  78.  
  79. function OpenModal(GM_config) {
  80. let modal = document.body.appendChild(document.createElement("div"));
  81. modal.id = "modal";
  82. Object.assign(modal.style, {
  83. display: "block",
  84. position: "fixed",
  85. left: 0,
  86. top: 0,
  87. width: "100%",
  88. height: "100%",
  89. overflow: "auto",
  90. backgroundColor: "rgba(0,0,0,0.7)"
  91. });
  92.  
  93. modal.addEventListener("click", function (e) {
  94. // when modal clicked
  95. if (e.target === this) {
  96. // close the config dialog
  97. GM_config.close();
  98. }
  99. });
  100. document.body.style.overflow = "hidden";
  101. }
  102.  
  103. GM_config.init({
  104. 'id': 'EmporniumEnhancementsConfig',
  105. 'title': 'Empornium Deluxe Mode Configuration',
  106. 'fields': {
  107. 'AlwaysHeader' : {
  108. 'label': 'Always keep header in view',
  109. 'type': 'checkbox',
  110. 'default': false
  111. },
  112. 'AutoDismiss': {
  113. 'label': 'Auto-dismiss login timeout notification',
  114. 'type': 'checkbox',
  115. 'default': false
  116. },
  117. 'AutoOpenFileList': {
  118. 'label': 'Auto-open filelist',
  119. 'type': 'checkbox',
  120. 'default': false
  121. },
  122. 'AutoOpenSpoilers': {
  123. 'label': 'Auto-open hidden text / spoilers',
  124. 'type': 'checkbox',
  125. 'default': false
  126. },
  127. 'AutoThankUploader': {
  128. 'label': 'Auto-thank the uploader upon clicking download / freeleech / doubleseed',
  129. 'type': 'checkbox',
  130. 'default': false
  131. },
  132. 'ShowImages': {
  133. 'label': 'Display hover images inline',
  134. 'type': 'checkbox',
  135. 'default': false
  136. },
  137. 'ShowRatioGoals': {
  138. 'label': 'Display ratio goals table on the Bonus Shop page (experimental)',
  139. 'type': 'checkbox',
  140. 'default': false
  141. },
  142. 'JumpToTop': {
  143. 'label': "Insert 'Jump to Top' link onto bottom-right corner of all pages",
  144. 'type': 'checkbox',
  145. 'default': false
  146. },
  147. 'StripAnonym': {
  148. 'label': 'Strip url anonymizers from links',
  149. 'type': 'checkbox',
  150. 'default': false
  151. },
  152. 'CopyClearBottomNotifs': {
  153. 'label': 'Move "clear" and "clear selected" links onto bottom of matched groups',
  154. 'type': 'checkbox',
  155. 'default': false
  156. },
  157. 'HideClearAll': {
  158. 'label': 'Hide "Clear" and "clear all" links to prevent accidental clearing',
  159. 'type': 'checkbox',
  160. 'default': false
  161. },
  162. 'AutoCheckNotif': {
  163. 'label': 'When the link is clicked, check the torrent\'s checkbox for manual clearing',
  164. 'type': 'checkbox',
  165. 'default': false
  166. },
  167. 'PreventNewWindow': {
  168. 'label': 'Prevent single-click links from opening a new window',
  169. 'type': 'checkbox',
  170. 'default': false
  171. },
  172. 'HideSeeded': {
  173. 'label': 'Hide currently seeding torrents',
  174. 'type': 'checkbox',
  175. 'default': false
  176. },
  177. 'HideLeeching': {
  178. 'label': 'Hide currently leeching torrents',
  179. 'type': 'checkbox',
  180. 'default': false
  181. },
  182. 'HideGrabbed': {
  183. 'label': 'Hide previously grabbed torrents [incomplete download]',
  184. 'type': 'checkbox',
  185. 'default': false
  186. },
  187. 'HideSnatched': {
  188. 'label': 'Hide previously snatched torrents [finished]',
  189. 'type': 'checkbox',
  190. 'default': false
  191. },
  192. 'FilterFilesize': {
  193. 'label': 'Only display torrents in the filesize range:',
  194. 'type': 'checkbox',
  195. 'default': false
  196. },
  197. 'FilterTags': {
  198. 'label': 'Hide torrents that contain any of the following tags (black list):',
  199. 'type': 'checkbox',
  200. 'default': false
  201. },
  202. 'TagListing': {
  203. 'label': '(comma-separated list)',
  204. 'type': 'textarea',
  205. 'title': 'black list',
  206. 'default': 'bbc, big.black.cock, bbw, fat, obese, hairy, gay, trans, tranny, transsexual, scat, feces, poop, puke, vomit, censored'
  207. },
  208. 'OnlyShowTheseTags': {
  209. 'label': 'Hide torrents that do <u>not</u> contain any of the following tags (must-have list):',
  210. 'type': 'checkbox',
  211. 'default': false
  212. },
  213. 'OnlyShowTagListing': {
  214. 'label': '(comma-separated list)',
  215. 'type': 'textarea',
  216. 'title': 'must-have list',
  217. 'default': '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'
  218. }
  219. },
  220. 'css': '#EmporniumEnhancementsConfig { background-color:#000525 !important; width: auto!important; height: auto!important; }\
  221. #EmporniumEnhancementsConfig_wrapper { background-color:#000525 !important; color:#2C8466 !important; width: 900px!important; margin-left: auto!important; margin-right: auto!important; }\
  222. #EmporniumEnhancementsConfig_field_TagListing, #EmporniumEnhancementsConfig_field_OnlyShowTagListing { width: 870px; height: 65px; }\
  223. #EmporniumEnhancementsConfig_FilterFilesize_var, #EmporniumEnhancementsConfig_TagListing_var { border-bottom: 3px solid #2C8466 !important; }\
  224. #EmporniumEnhancementsConfig_resetLink { color: #2C8466 !important; text-decoration: none !important; }\
  225. select, button, textarea, input:not([type=checkbox]) { background-color: #0E2D4A; color: silver; }\
  226. button {border-radius:5px}\
  227. #lowerNumber, #higherNumber { width: 50px }\
  228. .accordion {\
  229. /*background-color: #eee;\
  230. color: #444;*/\
  231. cursor: pointer;\
  232. padding: 18px;\
  233. width: 100%;\
  234. border: none;\
  235. text-align: center;\
  236. outline: none;\
  237. font-size: 15px;\
  238. transition: 0.4s;\
  239. }\
  240. \
  241. .active, .accordion:hover {\
  242. background-color: #133C5F; \
  243. }\
  244. \
  245. .panel {\
  246. padding: 0 18px;\
  247. display: none;\
  248. overflow: hidden;\
  249. }',
  250. 'events': {
  251. 'init': function() {
  252. // Set the value of the dummy field to the saved value
  253. //GM_config.set('customCSS', GM_config.get('validCSS'));
  254. },
  255. 'open': function(doc) {
  256. // Use a listener to update the hidden field when the dummy field passes validation
  257. /*GM_config.fields['customCSS'].node.addEventListener('change', function () {
  258. // get the current value of the visible field
  259. var customCSS = GM_config.get('customCSS', true);
  260.  
  261. // Only save valid CSS
  262. if (/\w+\s*\{\s*\w+\s*:\s*\w+[\s|\S]*\}/.test(customCSS)) {
  263. GM_config.set('validCSS', customCSS);
  264. }
  265. }, false);*/
  266.  
  267. /* logic to create the filesize range fields */
  268. let ref = GM_config.fields['FilterFilesize'].node.parentNode;
  269. let div = document.new("div").props({ id: "grpFilesize" }).appendTo(ref);
  270. let lowerNumber = document.new("input").props({ id: "lowerNumber", type: "text", title: "Lower range. Digits only." }).appendTo(div);
  271. let lowerUnits = document.new("select").props({ id: "lowerUnits" }).appendTo(div);
  272. let txt = document.new("label").props({ innerText: " to " }).appendTo(div);
  273. let higherNumber = document.new("input").props({ id: "higherNumber", type: "text", title: "Higher range. Digits only." }).appendTo(div);
  274. let higherUnits = document.new("select").props({ id: "higherUnits" }).appendTo(div);
  275.  
  276. // add select options
  277. let units = [ "KiB", "MiB", "GiB", "TiB" ];
  278. units.forEach(u => {
  279. document.new("option").props({ text: u, value: u }).appendTo(lowerUnits);
  280. document.new("option").props({ text: u, value: u }).appendTo(higherUnits);
  281. });
  282.  
  283. // set defaults
  284. lowerNumber.setAttribute("maxlength", 3);
  285. lowerNumber.value = "0";
  286.  
  287. higherNumber.setAttribute("maxlength", 3);
  288. higherNumber.value = "999";
  289.  
  290. higherUnits.value = "TiB";
  291. /* end of filesize range creation logic */
  292.  
  293. // attempt to parse stored range values
  294. try {
  295. let filesizeRange = JSON.parse(GM_getValue('fileSizeRange'));
  296. lowerNumber.value = filesizeRange.lowerNumber;
  297. lowerUnits.value = filesizeRange.lowerUnits;
  298. higherNumber.value = filesizeRange.higherNumber;
  299. higherUnits.value = filesizeRange.higherUnits;
  300. } catch {
  301. console.log("Check out the filesize range feature.");
  302. }
  303.  
  304. OpenModal(this);
  305. /* create the accordion UI */
  306. let wrapper = ref.parentNode;
  307. // define accordion layout
  308. div = RenderAccordion({
  309. "General": [
  310. "AlwaysHeader",
  311. "AutoDismiss",
  312. "JumpToTop",
  313. "PreventNewWindow",
  314. "StripAnonym"
  315. ],
  316. "Notifications": [
  317. "CopyClearBottomNotifs",
  318. "HideClearAll",
  319. "AutoCheckNotif"
  320. ],
  321. "Torrent Page": [
  322. "AutoOpenFileList",
  323. "AutoOpenSpoilers",
  324. "AutoThankUploader"
  325. ],
  326. "Torrent Listings": [
  327. "ShowImages",
  328. "HideSeeded",
  329. "HideLeeching",
  330. "HideGrabbed",
  331. "HideSnatched"
  332. ],
  333. "Filters": [
  334. "FilterFilesize",
  335. "FilterTags",
  336. "TagListing",
  337. "OnlyShowTheseTags",
  338. "OnlyShowTagListing"
  339. ],
  340. "Bonus": [
  341. "ShowRatioGoals"
  342. ]
  343. }, wrapper);
  344. wrapper.insertBefore(div, wrapper.firstChild.nextSibling);
  345. // wire-up the filter filesize checkbox to trigger the disabled state of its corresponding fields
  346. let chkFilterFilesize = wrapper.querySelector("#EmporniumEnhancementsConfig_field_FilterFilesize");
  347. if (chkFilterFilesize.checked == false) {
  348. chkFilterFilesize.nextSibling.querySelectorAll("input,select").forEach(field => {
  349. field.disabled = true;
  350. field.style.color = "gray";
  351. });
  352. }
  353.  
  354. chkFilterFilesize.addEventListener("click", function (e) {
  355. this.nextSibling.querySelectorAll("input,select").forEach(field => {
  356. if (this.checked == true) {
  357. field.removeAttribute("disabled");
  358. field.style.color = "silver";
  359. } else {
  360. field.disabled = true;
  361. field.style.color = "gray";
  362. }
  363. });
  364. });
  365.  
  366. // wire-up the filter tags checkbox to trigger the disabled state of its textbox
  367. let chkFilterTags = wrapper.querySelector("#EmporniumEnhancementsConfig_field_FilterTags");
  368. if (chkFilterTags.checked == false) {
  369. let txtTagListing = wrapper.querySelector("#EmporniumEnhancementsConfig_field_TagListing");
  370. txtTagListing.disabled = true;
  371. txtTagListing.style.color = "gray";
  372. }
  373.  
  374. chkFilterTags.addEventListener("click", function (e) {
  375. let txtTagListing = wrapper.querySelector("#EmporniumEnhancementsConfig_field_TagListing");
  376. if (this.checked == true) {
  377. txtTagListing.removeAttribute("disabled");
  378. txtTagListing.style.color = "silver";
  379. } else {
  380. txtTagListing.disabled = true;
  381. txtTagListing.style.color = "gray";
  382. }
  383. });
  384.  
  385. // wire-up the must-have tags checkbox to trigger the disabled state of its textbox
  386. let chkOnlyShowTheseTags = wrapper.querySelector("#EmporniumEnhancementsConfig_field_OnlyShowTheseTags");
  387. if (chkOnlyShowTheseTags.checked == false) {
  388. let txtOnlyShowTagListing = wrapper.querySelector("#EmporniumEnhancementsConfig_field_OnlyShowTagListing");
  389. txtOnlyShowTagListing.disabled = true;
  390. txtOnlyShowTagListing.style.color = "gray";
  391. }
  392.  
  393. chkOnlyShowTheseTags.addEventListener("click", function (e) {
  394. let txtOnlyShowTagListing = wrapper.querySelector("#EmporniumEnhancementsConfig_field_OnlyShowTagListing");
  395. if (this.checked == true) {
  396. txtOnlyShowTagListing.removeAttribute("disabled");
  397. txtOnlyShowTagListing.style.color = "silver";
  398. } else {
  399. txtOnlyShowTagListing.disabled = true;
  400. txtOnlyShowTagListing.style.color = "gray";
  401. }
  402. });
  403. },
  404. 'save': function(forgotten) {
  405. let ref = GM_config.fields['FilterFilesize'].node.parentNode;
  406. let lowerNumber = ref.querySelector("#lowerNumber");
  407. let lowerUnits = ref.querySelector("#lowerUnits");
  408. let higherNumber = ref.querySelector("#higherNumber");
  409. let higherUnits = ref.querySelector("#higherUnits");
  410.  
  411. // validate filesize number contraints
  412. if (/\D/.test(lowerNumber.value) || lowerNumber.value.length === 0) {
  413. console.log("Lower number contains non-digit or empty.");
  414. lowerNumber.style = "border: 1px solid red";
  415. lowerNumber.focus();
  416. lowerNumber.addEventListener("keydown", function () { lowerNumber.style = ""; });
  417. } else if (/\D/.test(higherNumber.value) || higherNumber.value.length === 0) {
  418. console.log("Higher number contains non-digit or empty.");
  419. higherNumber.style = "border: 1px solid red";
  420. higherNumber.focus();
  421. higherNumber.addEventListener("keydown", function () { higherNumber.style = ""; });
  422. } else {
  423. let filesizeRange = JSON.stringify({ "lowerNumber": lowerNumber.value, "lowerUnits": lowerUnits.value, "higherNumber": higherNumber.value, "higherUnits": higherUnits.value });
  424. GM_setValue('fileSizeRange', filesizeRange);
  425.  
  426. // reload on successful save
  427. location.reload();
  428. }
  429. },
  430. 'close': function() {
  431. // remove modal element on close
  432. document.body.removeChild(document.querySelector("#modal"));
  433. document.body.style.overflow = "";
  434. }
  435. }
  436. });
  437.  
  438. GM_registerMenuCommand('Empornium Deluxe Mode Configuration', function () {
  439. GM_config.open();
  440. });
  441.  
  442. function myRound(x, places) {
  443. let trunc = Math.pow(10, places);
  444. return Math.round(x * trunc) / trunc;
  445. }
  446.  
  447. function Insert_JumpToTop() {
  448. if (GM_config.get('JumpToTop')) {
  449. // create a div fixed in the bottom-right corner
  450. let jumpDiv = document.createElement("div");
  451. Object.assign(jumpDiv.style, {
  452. position: "fixed",
  453. bottom: "5px",
  454. right: "5px",
  455. textAlign: "right"
  456. });
  457.  
  458. // create the 'Jump to Top' link
  459. let anchor = document.createElement("a");
  460. anchor.innerText = "Jump to Top";
  461. anchor.href = "javascript:window.scrollTo(0, 0)";
  462.  
  463. // append the link to the corner div
  464. jumpDiv.appendChild(anchor);
  465.  
  466. // append the entire element to the body of the page
  467. document.body.appendChild(jumpDiv);
  468. }
  469. }
  470.  
  471. function Affix_Header() {
  472. if (GM_config.get('AlwaysHeader')) {
  473. if (document.querySelectorAll("#header").length > 0) {
  474. // affix the header into position
  475. document.querySelector("#header").style.cssText = "position: fixed !important; top: 0px; left: 0px;";
  476. // shift the contents down to account for missing space
  477. document.querySelector("#content").style.cssText = "margin-top:120px;";
  478. }
  479. }
  480. }
  481.  
  482. function Strip_Anon(links) {
  483. if (GM_config.get('StripAnonym')) {
  484. // list of url anonymizers to remove
  485. let anonymizers = [ "http://anonym.to/?", "http://anon.now.im/?" ];
  486.  
  487. // loop over each link
  488. links.forEach(link => {
  489. // loop thru the list of anonymizers
  490. anonymizers.forEach(anonymizer => {
  491. // if link contains current anonymizer
  492. if (link.href.indexOf(anonymizer) >= 0) {
  493. // replace it with empty string
  494. link.href = link.href.replace(anonymizer, "");
  495. }
  496. });
  497. });
  498. }
  499. }
  500.  
  501. function Prevent_NewWindow(links) {
  502. if (GM_config.get('PreventNewWindow')) {
  503. // loop over each link
  504. links.forEach(link => {
  505. // if a new window target has been set for current link
  506. if (link.target.length > 0) {
  507. // remove its target
  508. link.target = '';
  509. }
  510. });
  511. }
  512. }
  513.  
  514. function AutoOpen_Spoilers(links) {
  515. if (GM_config.get('AutoOpenSpoilers')) {
  516. // find all spoiler links
  517. links.filter(r => r.innerHTML === "Show").forEach(link => {
  518. // click to unhide
  519. link.click();
  520. });
  521. }
  522. }
  523.  
  524. function AutoDismiss_LoginTimeout() {
  525. if (GM_config.get('AutoDismiss')) {
  526. if (document.querySelectorAll("#flashClose").length > 0) {
  527. document.querySelector("#flashClose").click()
  528. }
  529. }
  530. }
  531.  
  532. function RedirectTo_LoginScreen(links) {
  533. if (links.filter(r => r.innerHTML === "Login").length > 0) {
  534. window.location.href += "login";
  535. }
  536. }
  537.  
  538. function SetFocus_LoginForm() {
  539. document.querySelector("input[name=username]").focus();
  540. }
  541.  
  542. function Show_RatioGoals() {
  543. if (GM_config.get('ShowRatioGoals')) {
  544. var stats = document.querySelectorAll(".stat");
  545. var units = [ "KiB", "MiB", "GiB", "TiB" ];
  546.  
  547. var ratio = parseFloat(stats[5].innerText);
  548. var down = stats[3].innerText;
  549. var up = stats[1].innerText;
  550.  
  551. var upUnitsIdx = units.indexOf(up.substring(1 + up.indexOf(" ")));
  552. var downUnitsIdx = units.indexOf(down.substring(1 + down.indexOf(" ")));
  553.  
  554. var unitsDiff = parseInt(Math.round(upUnitsIdx - downUnitsIdx));
  555. var displayUnits = units[downUnitsIdx];
  556.  
  557. up = up.replace(/,/g, "");
  558. up = parseFloat(up.substring(0, up.indexOf(" ")));
  559. down = down.replace(/,/g, "");
  560. down = parseFloat(down.substring(0, down.indexOf(" ")));
  561.  
  562. // convert totals to same units
  563. if (unitsDiff < 0) {
  564. down *= Math.pow(1024, -unitsDiff);
  565. displayUnits = units[upUnitsIdx];
  566. } else if (unitsDiff > 0) {
  567. up *= Math.pow(1024, unitsDiff);
  568. }
  569.  
  570. var diff = down / 100.0;
  571. var currAmount = Math.abs((ratio + 0.01) * down - up);
  572.  
  573. let strHtml = "<table style=\"text-align:center !important;margin: 0px auto; width:50%;\">\
  574. <tbody>\
  575. <tr>\
  576. <td style=\"width:90px;text-align:center;\">U/L differential</td>\
  577. <td style=\"width:90px;text-align:center;\"> for ratio </td>\
  578. <td style=\"width:90px;text-align:center;\"> Amount to U/L </td>\
  579. </tr>";
  580.  
  581. for (let i = 1; i <= 10; i++) {
  582. var currRatio = i/100.0 + ratio;
  583.  
  584. // alternate background color
  585. var style = "";
  586. if (i % 2 != 0) {
  587. style = " style=\"background-color:#222222 !important;\"";
  588. }
  589.  
  590. 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>";
  591.  
  592. currAmount += diff;
  593. }
  594.  
  595. strHtml += "</tbody></table>";
  596.  
  597. var content = document.querySelector("#content");
  598. content.innerHTML = strHtml + content.innerHTML;
  599. }
  600. }
  601.  
  602. function Hide_Seeded(torrents) {
  603. if (GM_config.get('HideSeeded')) {
  604. torrents.filter(r => r.querySelectorAll(".icon_disk_seed").length > 0).forEach(itemRow => { itemRow.style = "display:none"; });
  605. }
  606. }
  607.  
  608. function Hide_Grabbed(torrents) {
  609. if (GM_config.get('HideGrabbed')) {
  610. torrents.filter(r => r.querySelectorAll(".icon_disk_grabbed").length > 0).forEach(itemRow => { itemRow.style = "display:none"; });
  611. }
  612. }
  613.  
  614. function Hide_Snatched(torrents) {
  615. if (GM_config.get('HideSnatched')) {
  616. torrents.filter(r => r.querySelectorAll(".icon_disk_snatched").length > 0).forEach(itemRow => { itemRow.style = "display:none"; });
  617. }
  618. }
  619.  
  620. function Hide_Leeching(torrents) {
  621. if (GM_config.get('HideLeeching')) {
  622. torrents.filter(r => r.querySelectorAll(".icon_disk_leech").length > 0).forEach(itemRow => { itemRow.style = "display:none"; });
  623. }
  624. }
  625.  
  626. function Filter_Tags(torrents) {
  627. if (GM_config.get('FilterTags')) {
  628. // grab the filters from the settings
  629. let filters = GM_config.get('TagListing').replace(/[\n\r\s]/g, "").split(',');
  630.  
  631. // loop over each torrent
  632. torrents.forEach(itemRow => {
  633. // grab the current torrent's list of tags
  634. let tags = itemRow.querySelector(".tags").innerText.split(" ");
  635.  
  636. // if the filter keywords and tags have items in common
  637. if (filters.intersects(tags)) {
  638. // hide this torrent row
  639. itemRow.style = "display:none";
  640. console.log("Filtered these tags: " + JSON.stringify(filters.intersect(tags)));
  641. }
  642. });
  643. }
  644. }
  645.  
  646. function Display_ImagesInline(torrents) {
  647. if (GM_config.get('ShowImages')) {
  648. // loop over each torrent
  649. torrents.forEach(itemRow => {
  650. // if current torrent row contains a hover script and a cats_col class of element exists within it
  651. if (itemRow.querySelectorAll("script").length > 0 && itemRow.querySelectorAll("[class*=cats_col]").length > 0) {
  652. // extract the image-generating html from the hover script
  653. let strHtml = itemRow.querySelector("script").innerHTML.replace(/[\[\]\{\}\(\)\\\|]/g, "");
  654. let start = strHtml.indexOf("\"")+1;
  655. let end = strHtml.lastIndexOf("\"");
  656. strHtml = strHtml.substring(start, end);
  657.  
  658. // create a div within which to place the image
  659. let div = document.createElement("div");
  660.  
  661. // hide the cats_col's child elements which contain a definite title to make room for the image
  662. Array.from(itemRow.querySelector("[class*=cats_col]").childNodes).filter(r => r.title !== undefined).forEach(cat => { cat.style.display = "none"; });
  663.  
  664. // add the html to generate the image to the div
  665. div.innerHTML = strHtml;
  666.  
  667. // display the image in the torrent row
  668. itemRow.querySelector("[class*=cats_col]").appendChild(div);
  669. }
  670. });
  671. }
  672. }
  673.  
  674. function Hide_ClearAll(links) {
  675. if (GM_config.get("HideClearAll")) {
  676. // hide "clear all" and "Clear"
  677. links.filter(r => r.innerHTML === "(clear all)" || r.innerHTML === "Clear").forEach(link => { link.style.display = "none"; });
  678. }
  679. }
  680.  
  681. function AutoCheck_ClickedTorrent(torrents) {
  682. if (GM_config.get("AutoCheckNotif")) {
  683. // loop over entire torrent list
  684. torrents.forEach(itemRow => {
  685. // filter-out links on current torrent that do not contain "/torrents.php?id"
  686. Array.from(itemRow.querySelectorAll("a")).filter(r => r.href.indexOf("/torrents.php?id") > -1).forEach(link => {
  687. link.addEventListener("mousedown", function (e) {
  688. // activate checkbox of current torrent if notification link was clicked
  689. itemRow.querySelector("input[type=checkbox]").checked = true;
  690. });
  691. });
  692. });
  693. }
  694. }
  695.  
  696. function Move_ClearToGroupBottom() {
  697. if (GM_config.get("CopyClearBottomNotifs")) {
  698. // look for the torrent_table class of elements
  699. document.querySelectorAll(".torrent_table").forEach(t => {
  700. // find the current table's previous sibling's previous sibling
  701. let ps = t.previousSibling.previousSibling;
  702. // clone the element
  703. let c = ps.cloneNode(true);
  704. // insert at the bottom
  705. t.parentNode.insertBefore(c, t.nextSibling);
  706. ps.innerHTML = ps.innerHTML.toString().match(/(\w+\s){4}/gm);
  707. });
  708. }
  709. }
  710.  
  711. function Filter_Filesizes(torrents) {
  712. if (GM_config.get("FilterFilesize")) {
  713. let units = [ "KiB", "MiB", "GiB", "TiB" ];
  714. let filesizeRange = JSON.parse(GM_getValue('fileSizeRange'));
  715.  
  716. // loop over each torrent
  717. torrents.forEach(itemRow => {
  718. // retrieve filesize of current torrent
  719. let currSize = Array.from(itemRow.querySelectorAll(".nobr")).filter(r => /^[\d\.,]+\s.iB$/.test(r.innerText))[0].innerText.split(" ");
  720.  
  721. // hide row if units of current row are less than units of min range
  722. if (units.indexOf(currSize[1]) < units.indexOf(filesizeRange.lowerUnits)) {
  723. itemRow.style.display = "none";
  724. } else if (currSize[1] === filesizeRange.lowerUnits) {
  725. // hide row if units match and filesize is less than min range
  726. if (parseFloat(currSize[0]) < parseInt(filesizeRange.lowerNumber)) {
  727. itemRow.style.display = "none";
  728. }
  729. }
  730.  
  731. // hide row if units of current row are greater than units of max range
  732. if (units.indexOf(currSize[1]) > units.indexOf(filesizeRange.higherUnits)) {
  733. itemRow.style.display = "none";
  734. } else if (currSize[1] === filesizeRange.higherUnits) {
  735. // hide row if units match and filesize is greater than max range
  736. if (parseFloat(currSize[0]) > parseInt(filesizeRange.higherNumber)) {
  737. itemRow.style.display = "none";
  738. }
  739. }
  740. });
  741. }
  742. }
  743.  
  744. function Draw_MenuItem() {
  745. if (document.querySelector(".username") != null) {
  746. // config icon - wrench & screwdriver depicted
  747. let icon = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA\
  748. u0lEQVQ4jZ2SMQ4CMQwERyiICqEr+EGgRBelpkvLI3kDD+IBdDQUFKbJIcdyTqezlGazu7\
  749. ZXBlM55+1ajFLyYS2mQanv4hFDCNP/rKNUoid+NAZql5MxFODriMtkEGPcNV2BsxIL8O6J\
  750. vfVE7fd/w7C/LhFjOosxTEvETTnTjK7YO4hKDM40o+bZEO0qnwrZbNKSHF4OZoNtK6V4VC\
  751. QtnkoAUYZuZwE2vRHVdbqXeO90ttgTuEEnRA+cw36EkV9UhABsAgAAAABJRU5ErkJggg==";
  752. // find the user nav element
  753. let navbar = document.querySelector(".username").parentNode.querySelector("ul");
  754. // clone a list item layout
  755. let configNode = navbar.querySelector("li").cloneNode(true);
  756.  
  757. // wire-up the config element
  758. configNode.id = "deluxe_config";
  759. configNode.innerHTML = "";
  760. let anchor = document.new("a").appendTo(configNode);
  761. anchor.title = "Empornium Deluxe Mode Configuration";
  762. anchor.innerHTML = '<img src="' + icon + '" style="filter:invert(100%);"/> Deluxe Mode Config';
  763. anchor.href = "javascript:void(0)";
  764. anchor.addEventListener("click", function (e) {
  765. GM_config.open();
  766. });
  767.  
  768. // display config link as first item in the user nav
  769. navbar.insertBefore(configNode, navbar.firstChild);
  770. }
  771. }
  772.  
  773. function AutoThank_Uploader() {
  774. if (GM_config.get("AutoThankUploader")) {
  775. // .blueButton => Download
  776. // .greenButton => Freeleech
  777. // .orangeButton => Doubleseed
  778. // look for the download / freeleech / doubleseed buttons
  779. Array.from(document.querySelectorAll(".blueButton,.greenButton,.orangeButton")).forEach(btn => {
  780. // wire-up event to auto-click thanks upon downloading
  781. btn.addEventListener("click", function (e) {
  782. window.setTimeout(function () {
  783. // if thanks button not disabled
  784. if (!document.querySelector("#thanksbutton").disabled) {
  785. // invoke it
  786. document.querySelector("#thanksbutton").click();
  787. }
  788. // wait 500ms so as not to interrupt download request
  789. }, 500);
  790. });
  791. });
  792. }
  793. }
  794.  
  795. function AutoOpen_FileList(links) {
  796. if (GM_config.get("AutoOpenFileList")) {
  797. links.filter(r => r.innerHTML === "(View Filelist)")[0].click();
  798. }
  799. }
  800.  
  801. function OnlyShow_TheseTags(torrents) {
  802. if (GM_config.get('OnlyShowTheseTags')) {
  803. // grab the filters from the settings
  804. let filters = GM_config.get('OnlyShowTagListing').replace(/[\n\r\s]/g, "").split(',');
  805.  
  806. // loop over each torrent
  807. torrents.filter(r => r.style.display !== "none").forEach(itemRow => {
  808. // grab the current torrent's list of tags
  809. let tags = itemRow.querySelector(".tags").innerText.split(" ");
  810.  
  811. // if the filter keywords and tags do not have items in common
  812. if (!filters.intersects(tags)) {
  813. // hide this torrent row
  814. itemRow.style = "display:none";
  815. console.log("These tags aren't whitelisted and therefore the torrent was hidden: " + JSON.stringify(tags.filter(r => r !== "")));
  816. }
  817. });
  818. }
  819. }
  820.  
  821.  
  822.  
  823. // main
  824. (function() {
  825. 'use strict';
  826.  
  827. AutoDismiss_LoginTimeout();
  828. Draw_MenuItem();
  829.  
  830. let links = Array.from(document.querySelectorAll("a"));
  831. let torrents = Array.from(document.querySelectorAll(".torrent"));
  832.  
  833. // page match rules
  834. if (/empornium\.me\/?$/.test(window.location.href)) {
  835. RedirectTo_LoginScreen(links);
  836. } else if (/empornium\.me\/login$/.test(window.location.href)) {
  837. SetFocus_LoginForm();
  838. } else {
  839. // occurs on all authenticated pages
  840. Affix_Header();
  841. Strip_Anon(links);
  842. Prevent_NewWindow(links);
  843. Insert_JumpToTop();
  844.  
  845.  
  846. if (/torrents\.php.+action=notify/.test(window.location.href)) {
  847. // notifications page
  848. Hide_ClearAll(links);
  849. Move_ClearToGroupBottom();
  850. AutoCheck_ClickedTorrent(torrents);
  851. }
  852.  
  853. if (/(torrents|top10|user)\.php/.test(window.location.href) && !/(\?|&)id=/.test(window.location.href)) {
  854. // torrents / top10 / user - lists of torrents
  855. Filter_Tags(torrents);
  856. Filter_Filesizes(torrents);
  857. OnlyShow_TheseTags(torrents);
  858.  
  859. Hide_Seeded(torrents);
  860. Hide_Grabbed(torrents);
  861. Hide_Snatched(torrents);
  862. Hide_Leeching(torrents);
  863.  
  864. Display_ImagesInline(torrents);
  865. } else if (/torrents\.php\?id=\d+/.test(window.location.href)) {
  866. // single torrent landing page
  867. AutoOpen_Spoilers(links);
  868. AutoOpen_FileList(links);
  869. AutoThank_Uploader();
  870. } else if (/bonus\.php/.test(window.location.href)) {
  871. // bonus page
  872. Show_RatioGoals();
  873. }
  874. }
  875. })();