Greasy Fork

MAM Ratio Protect

Warns about downloading based on resulting Ratio Loss due to forgetting to buy w/FL

目前为 2021-03-07 提交的版本。查看 最新版本

// ==UserScript==
// @name MAM Ratio Protect
// @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.71
// @description (3/7/21)
// @grant none
// @run-at document-end
// ==/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;
let rcRow; //Used in body and functions

//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)

/* Easter Egg bonus features, uncomment to use! */
//Hide banner on book pages if not using MAM+
//document.getElementById("msb").style.display = "none";

//Re-title tab to make it easier to find a book tab! v1.66
document.title=document.title.replace('Details for torrent "', '');
//This makes Bookmark titles easier to read as well!
// See also: https://greasyfork.org/en/scripts/418820-mam-user-page-re-title

/* End Easter Eggs */

// 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]}

/** 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
			`<div class="torDetRow" id="Mrp_row"><div class="torDetLeft">${label}</div><div class="torDetRight ${rowClass}"><span id="mp_foobar"></span></div></div>`);
            return document.querySelector(`.${rowClass} #mp_foobar`);
        }
}

/*
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("xhr status: " + ResultObj.success);
				if (ResultObj.success && ResultObj.type == "personal FL") { // Return download button etc. to normal after FL purchase (v1.6)
					// bookmark operations return {"success": true, "action": "add"} Specific FL test in v1.63!
					dlBtn.innerHTML = "Download";
					dlBtn.style.backgroundColor="dodgerblue";
					dlLabel.innerHTML = ""; //Clear ratio loss
					//document.getElementById("Mrp_row").style.visibility = "hidden"; //Wastes space
                    document.getElementById("Mrp_row").style.display = "none"; //Restore w/ "block"
					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);

if (DEBUG) console.log("Declaring fetchUD()");
function fetchUD() { //Fetch ratio Uploaded numerator, and Downloaded denominator, then show calculations
		if (DEBUG) console.log("Fetching user data");
		fetch('https://www.myanonamouse.net/jsonLoad.php') //Greasemonkey/Violentmonky seem to need FQDN instead of partial URL (v1.65)
		.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.innerHTML = "<b>" + formatBytes(recovU) + "</b>&nbsp; Uploaded Needed to Restore Current Ratio.<br><b>" +
			comma(Math.floor(125*recovU/268435456)) + "</b> Bonus Points to purchase.<br>" +
            "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.innerHTML += "<br>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.innerHTML = "Try at most one reload to resolve error: " + error
		+ '<br>and then <a href="https://greasyfork.org/en/scripts/416189-mam-ratio-protect/feedback" target="_blank">report this exact error message</a>'
		+ " along with the browser and userscript manager you are using including their version numbers." ; // v1.65
// Produced on 404: SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data
		});
}

// 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);
rnew = rnew.replace(/[A-z]/g,""); // (v.1.71) to address no space before "This can't be made site FL due to no author set" t/73005
//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);

	// Create button that will load data and insert calculations (and slow ajax calls to server)
	rcRow.innerHTML = '<button id="Mrp_btn">View Calculations</button>';
	document.getElementById("Mrp_btn").addEventListener("click", fetchUD);

  }

    // 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";
    }
}