// ==UserScript== // @name MAM Ratio Protect BETA // @namespace yyyzzz999 // @author yyyzzz999 // @description Warns about downloading based on resulting Ratio Loss due to forgetting to buy w/FL // @include https://www.myanonamouse.net/t/* // @version 1.62 // @description (12/12/20) // @grant none // @run-at document-end // @downloadURL none // ==/UserScript== // Many Thanks to GardenShade & ooglyboogly for advice, testing, and code contributions! /*jshint esversion: 6 */ /*eslint no-multi-spaces:0 */ //stop pestering me 'cause I learned to type with double spaces! // Release downloadURL: https://greasyfork.org/en/scripts/416189-mam-ratio-protect let xhr; //Used in body and functions let rcRow; let UserObj; //let tHash = ""; //Hexcode hash for this torrent let DEBUG =0; // Debugging mode on (1) or off (0) added in (v1.54) verbose (2) (v1.6) //Hide banner on book pages if not using MAM+ //document.getElementById("msb").style.display = "none"; // Functions: //https://blog.abelotech.com/posts/number-currency-formatting-javascript/ function comma(num) { // add commas to a number return num.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,') } function formatBytes(a,b=2){if(0===a)return"0 Bytes"; const c=0>b?0:b,d=Math.floor(Math.log(a)/Math.log(1024)); return parseFloat((a/Math.pow(1024,d)).toFixed(c))+" "+["Bytes","KB","MB","GB","TB","PB","EB","ZB","YB"][d]} https://blog.abelotech.com/posts/number-currency-formatting-javascript/ /** hacked from MAM+ 4.2.20 Line 222 Always inserted line at beginning or end of page block until removed parentElement before insertAdjacentHTML * Add a new TorDetRow and return the inner div * @param tar The row to be targetted * @param label The name to be displayed for the new row * @param rowClass The row's classname (should start with mp_) */ function myaddTorDetailsRow(tar, label, rowClass) { if (tar == null ) { //why originally === assignment? throw new Error(`myAdd Tor Details Row: empty node @ ${tar}`); } else { tar.insertAdjacentHTML('beforebegin', // changed from afterbegin so I can position before .torDetBottom as nth child changes w/MAM+ // and Torrent: ratio line has no id or unique CSS `
${label}
`); return document.querySelector(`.${rowClass} .flex`); } } /* https://stackoverflow.com/questions/629671/how-can-i-intercept-xmlhttprequests-from-a-greasemonkey-script Spy on all AJAX request/response to see when FL is purchased This works in Basilisk Scratchpad, Tampermonkey w/Firefox, but not Greasmonkey 3.9 in Basilisk Problem: it also looks at our own AJAX request so we return early if we see the user data object */ let ResultObj; // I scoped this out of the function in case I want to reference it later in other contexts/functions // This is where we react after FL purchase (function(open) { XMLHttpRequest.prototype.open = function() { this.addEventListener("readystatechange", function() { if (DEBUG >2) console.log(this.readyState); if (DEBUG >2) console.log(this.responseText); if (this.readyState == 4 && this.status == 200) { ResultObj = JSON.parse(this.responseText); if ( ResultObj.uid ) return; //if getting user data in this script w/ fetch('/jsonLoad.php') if (DEBUG >1) console.log("Response: " + this.responseText); if (DEBUG) console.log("FL Purchase status: " + ResultObj.success); if (ResultObj.success) { // Return download button etc. to normal after FL purchase (v1.6) dlBtn.innerHTML = "Download"; dlBtn.style.backgroundColor="dodgerblue"; dlLabel.innerHTML = ""; //Clear ratio loss //rcRow.display = "none"; //Why no work? rcRow.hidden = "true"; //Why no work? rcRow.textContent = ""; if (DEBUG) console.log("Seedbonus: " + ResultObj.seedbonus); if( document.getElementById("tmFW") && ResultObj.FLleft) // If FL Wedges: are displayed in top menu & we have new value so update it document.getElementById("tmFW").textContent=ResultObj.textContent="FL Wedges: " + ResultObj.FLleft; // Why doesn't MAM already do this? } } }, false); open.apply(this, arguments); }; })(XMLHttpRequest.prototype.open); // Main Program // The download text area let dlBtn = document.getElementById("tddl"); // The unused label area above the download text let dlLabel = document.querySelector("#download .torDetInnerTop"); // Would become ratio let rnew = 0; // FALSE if (document.getElementById("ratio").textContent.split(" ")[1].match(/become/) ) { rnew = document.getElementById("ratio").textContent.split(" ")[2].replace(/,/g,""); // (v1.54) // VIP expires date caused rdiff to be NaN in v1.53 bcause text crept in in v1.52 } if (DEBUG) console.log("rnew= " + rnew); //let rnew = document.getElementById("ratio").textContent.split("become ")[1].replace(/,/g,""); // broke w/On list for next FL pick //let rnew = document.getElementById("ratio").textContent.match(/\d*\,?\d+\.\d+/)[0].replace(/,/g,"''); //breaks at 1,000,000bp if (DEBUG) console.log("rnew= " + rnew); // For debugging // Current ratio - Version 1.52 and earlier broke when a ratio has a comma let rcur = document.getElementById("tmR").textContent.replace(/,/g,""); if (DEBUG) console.log("rcur= " + rcur); // For debugging // Seeding or downloading TRUE if "Actively Seeding" etc. let seeding = document.getElementById('DLhistory'); if (DEBUG) console.log("seeding= " + seeding); // Available FL wedges - for future use... (>v1.6) // Only visible if set on MAM in Preferences, Style, Main Menu, Top Menu //let wedgeAvail = document.getElementById('tmFW').textContent.split(":")[1].trim(); //only works if added to top menu // Probably more robust way of finding current FL, so use if avail. //if(wedgeAvail) console.log("tm wedgeAvail= " + wedgeAvail); // ELSE try finding in drop downs with Rel XPath //a[contains(text(),'FL Wedges: ')] or // CSS ul:nth-child(1) li.mmUserStats ul.hidden:nth-child(2) li:nth-child(7) > a:nth-child(1) // let wedgeAvail = document.querySelector('[aria-labelledby="userMenu"] li:nth-of-type(7)').textContent.split(':')[1].trim(); // or document.querySelector("ul:nth-child(1) li.mmUserStats ul.hidden:nth-child(2) li:nth-child(7) > a:nth-child(1)") // Only run the code if the new ratio exists and we found the current one if(rnew && rcur){ let rdiff = rcur-rnew; // Loss in ratio after download (if error in old browser use var instead of let) if (DEBUG) console.log("rdiff= " + rdiff); // For debugging if (seeding == null ) { // if NOT already seeding, downloading or VIP expires (v1.54) dlLabel.innerHTML = `Ratio loss ${rdiff.toFixed(4)}`; //changed from toPrecision(5) (v1.54) dlLabel.style.fontWeight = "normal"; //To distinguish from BOLD Titles // Add line under Torrent: detail for Cost data rcRow = myaddTorDetailsRow(document.querySelector("div[class='torDetBottom']"), 'Cost to Restore Ratio', 'mp_rcRow'); if (DEBUG) console.log("rcRow.innerHTML= " + rcRow.innerHTML); // Get user data for ratio numerator and denominator // Move to onlick function, that will be placed in rcRow.innerHTML here... if (DEBUG) console.log("Fetching user data"); fetch('/jsonLoad.php') .then(response => response.json()) .then(data => { //console.log(data); //if (DEBUG) console.log("U/D:",data.uploaded,data.downloaded); // Calculate & Display cost of download w/o FL let x=document.querySelector("div[id='size'] span").textContent.split(/\s+/); //Why didn't split(" ") work? if (DEBUG) console.log("x = " + x + ", x[0]= " + x[0] + ", x[1]= " + x[1] ); const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']; // I want to be around when we start sharing TB+ collections! ;-) let tsize = x[0] * Math.pow(1024, sizes.indexOf(x[1])); // Convert human notation to bytes, only used once so didn't make it a function if (DEBUG) console.log("tsize = " + tsize); let recovU = (data.uploaded*(data.downloaded+tsize))/data.downloaded - data.uploaded; rcRow.textContent = "To recover your current ratio you would need to upload about " + formatBytes(recovU) + ". This would cost about " + comma(Math.floor(125*recovU/268435456)) + " bonus points if completely obtained in the site store. " + "Contributing to the vault gives you on average almost one FL wedge per day at a cost of as little as 200 bonus points each. "; if (DEBUG) rcRow.textContent += "Calculations based on Up/Down ratio= " + data.uploaded + "/" + data.downloaded + ", aproximately " + comma(Math.floor(recovU)) + " future upload bytes, and a download size of " + comma(tsize) + " bytes."; }) // .textContent above prob. should be replaced with innerHTML for formatting and links etc. .catch((error) => { console.error('Error:', error); rcRow.textContent = "Try at most one reload to resolve error: " + error ; // Produced on 404: SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data }); /* replaced with above fetch() // API doc https://www.myanonamouse.net/api/endpoint.php/2/jsonLoad.php xhr = new XMLHttpRequest(); xhr.addEventListener("readystatechange", processRequest, false); xhr.onreadystatechange = processRequest; xhr.open('GET', "/jsonLoad.php", true); // Arguments seem to be ignored, but returns current user data parsed by processRequest xhr.send(); */ /* This doesn't work due to timing issues, and scrapped due to server load restrictions, sigh // Get exact torrent size via HASH document.querySelector("#filelistLink").dispatchEvent(new MouseEvent('click')); //setTimeout(function(){ document.querySelector("#filelistLink").dispatchEvent(new MouseEvent('click')); //}, 333); // Wait 1/3 second and rehide the hash let tHash = ""; if ( document.querySelector("div[id='filesDisplay'] h2") != null ) tHash = document.querySelector("div[id='filesDisplay'] h2").textContent.split(":")[1].trim(); //doesn't work until "View Filelist" clicked and https://www.myanonamouse.net/tor/filelist.php?torrentid=nnnnnn returns html if (DEBUG) console.log("tHash= " + tHash); */ } // Change this .3 number to your "trivial ratio loss" amount // These changes will always happen if the ratio conditions are met if(rdiff > 0.3){ dlBtn.style.backgroundColor="SpringGreen"; dlBtn.style.color="black"; } // Change this 1 number to your I never want to dl w/o FL ratio loss amount if(rdiff > 1){ dlBtn.style.backgroundColor="Red"; // Disable link to prevent download // dlBtn.style.pointerEvents="none"; // Uncomment (remove //) above line to disable the download button // maybe hide the button, and add the Ratio Loss warning in its place? dlBtn.innerHTML = "FL Recommended"; dlLabel.style.fontWeight = "bold"; // Change this .5 number to your "I need to think about using a FL ratio loss" amount }else if(rdiff > 0.5){ dlBtn.style.backgroundColor="Orange"; } } /* Replaced this code with newer fetch() //function copied from https://www.kirupa.com/html5/making_http_requests_js.htm // Used to query AJAX JSON JavaObjects to get more accurate numbers than shown on page function processRequest(e) { //console.log(xhr.responseText,xhr.readyState,xhr.status); if (xhr.readyState == 4 && xhr.status == 200) { UserObj = JSON.parse(xhr.responseText); // Get upload and download to the byte here, and calculations then placed in rcRow.textContent if (DEBUG) console.log("Uploaded: " + UserObj.uploaded); if (DEBUG) console.log("Downloaded: " + UserObj.downloaded); if (DEBUG >1) console.log("Response: " + xhr.responseText); rcRow.textContent = "Calculations based on Up/Down= " + UserObj.uploaded + "/" + UserObj.downloaded + " unfinished."; if (DEBUG) console.log("processRequest can see rcRow.textContent= " + rcRow.textContent); console.log(xhr.responseText); } } */