Greasy Fork is available in English.

Pinterest Plus

Show full size + working middle click to open new tab + open original image.

Versione datata 25/07/2020. Vedi la nuova versione l'ultima versione.

// ==UserScript==
// @name        Pinterest Plus
// @namespace   https://greasyfork.org/users/102866
// @description Show full size + working middle click to open new tab + open original image.
// @include     https://*.pinterest.*/*
// @require     https://code.jquery.com/jquery-3.4.1.min.js
// @author      TiLied
// @version     0.5.03
// @grant       GM_openInTab
// @grant       GM_listValues
// @grant       GM_getValue
// @grant       GM_setValue
// @grant       GM_deleteValue
// @require     https://greasemonkey.github.io/gm4-polyfill/gm4-polyfill.js
// @grant       GM.openInTab
// @grant       GM.listValues
// @grant       GM.getValue
// @grant       GM.setValue
// @grant       GM.deleteValue
// ==/UserScript==

class Options
{
	constructor(debug)
	{
		this.debug = debug;
	}

	get Debug()
	{
		let v =
		{
			debug: this.debug
		};

		return v;
	}

	set Debug(obj)
	{
		this.debug = obj["debug"];
	}

	//Start
	//async Methods/Functions GM_VALUE
	async HasValueGM(nameVal, optValue)
	{
		var vals = await GM.listValues();

		if (vals.length === 0)
		{
			if (optValue !== undefined)
			{
				GM.setValue(nameVal, optValue);
				return true;
			} else
			{
				return false;
			}
		}

		if (typeof nameVal !== "string")
		{
			return alert("name of value: '" + nameVal + "' are not string");
		}

		for (let i = 0; i < vals.length; i++)
		{
			if (vals[i] === nameVal)
			{
				return true;
			}
		}

		if (optValue !== undefined)
		{
			GM.setValue(nameVal, optValue);
			return true;
		} else
		{
			return false;
		}
	}
	async DeleteValuesGM(nameVal)
	{
		var vals = await GM.listValues();

		if (vals.length === 0 || typeof nameVal !== "string")
		{
			return;
		}

		switch (nameVal)
		{
			case "all":
				for (let i = 0; i < vals.length; i++)
				{
					if (vals[i] !== "adm")
					{
						GM.deleteValue(vals[i]);
					}
				}
				break;
			case "old":
				for (let i = 0; i < vals.length; i++)
				{
					if (vals[i] === "debug" || vals[i] === "debugA")
					{
						GM.deleteValue(vals[i]);
					}
				}
				break;
			default:
				for (let i = 0; i < vals.length; i++)
				{
					if (vals[i] === nameVal)
					{
						GM.deleteValue(nameVal);
					}
				}
				break;
		}
	}
	async UpdateGM(what)
	{
		var gmVal;

		switch (what)
		{
			case "options":
				gmVal = JSON.stringify(options.values);
				GM.setValue("pp_options", gmVal);
				break;
			default:
				alert("class:Options.UpdateGM(" + what + "). default switch");
				break;
		}
	}
	//async Methods/Functions GM_VALUE
	//End
}

class Main extends Options
{
	_SetLocalVal()
	{
		this.whatPage = 0;
		this.fullSize = false;
		this.login = null;
		this.oldWay = false;
		this.oneSecond = 1000;
		this.deltaTime = 1500;
	}
	
	constructor(debug, pFullSize)
	{
		super(debug);
		this.pFullSize = pFullSize;
	}

	get getValues()
	{
		return this.Debug.push(this.pFullSize);
	}

	set setValues(obj)
	{
		this.debug = obj["debug"];
		this.pFullSize = obj["pFullSize"];
		console.log(obj);
	}

	_Main()
	{
		console.log("Pinterest Plus v" + GM.info.script.version + " initialization");
		this._SetLocalVal();
		//Middle click
		document.addEventListener("click", function (e) { e.button === 1 && e.stopPropagation(); }, true);
		//Url handler for changing(If you don't like tabs)
		this.UrlHandler();
		//Place CSS in head
		this.SetCSS();
		//Set settings or create
		this.SetSettings(function ()
		{
			//check login
			if (main.debug) console.log($("main[data-test-id='unauthPinPage']"));

			if ($("main[data-test-id='unauthPinPage']").length !== 0)
				main.login = false;
			else
				main.login = true;

			if (main.debug) console.log("login: " + main.login);
			//Check on what page we are and switch. Currently only on pin page
			main.SwitchPage();
			console.log("Page number: " + main.whatPage + "/" + Page[main.whatPage] + " page");
		});
	}

	SetCSS()
	{
		$("head").append($("<!--Start of Pinterest Plus v" + GM.info.script.version + " CSS-->"));

		$("head").append($("<style type=text/css></style>").text("button.ppTrue \
		{                                         \
			border:2px solid black!important;     \
		}                                         \
		"));

		$("head").append($("<style type=text/css></style>").text("#myBtn \
		{                                         \
			align-items: center;\
			box-sizing: border-box;\
			color:#fff;\
			font-size: 16px;\
			font-weight: 700;\
			letter-spacing: -.4px;\
			padding: 10px;\
			padding-top: 10px;\
			padding-right: 14px;\
			padding-left: 14px;\
			padding-bottom: 10px;\
			margin-top: -4px;\
			border-style: solid;\
			border-width: 0px;\
		}                                         \
		"));

		$("head").append($("<style type=text/css></style>").text("#pp_divFullSize \
		{                                         \
			z-index: 500;!important;     \
			justify-content: center;\
			display: flex;\
		}                                         \
		"));

		$("head").append($("<!--End of Pinterest Plus v" + GM.info.script.version + " CSS-->"));
	}

	async SetSettings(callBack)
	{
		//THIS IS ABOUT pFullSize
		if (this.HasValueGM("ppFullSize", false))
		{
			this.pFullSize = await GM.getValue("ppFullSize");
		}

		//Console log prefs with value
		console.log("*prefs:");
		console.log("*-----*");
		var vals = await GM.listValues();

		//Find out that var in for block is not local... Seriously js?
		for (let i = 0; i < vals.length; i++)
		{
			console.log("*" + vals[i] + ":" + await GM.getValue(vals[i]));
		}
		console.log("*-----*");

		callBack();
	}

	SwitchPage()
	{
		switch (this.GetPage(document.URL))
	{
			case 1:
				break;
			case 2:
				this.HidePopup();
				break;
			case 4:
			case 5:
			case 6:
			case 10:
				break;
			case 3:
				this.HidePopup();
				this.SetUpForPin();
				break;
			default:
				break;
		}
	}

	//On what page are we?
	GetPage(url)
	{
		/*
		1-front page
		2-search page
		3-pin page
		4-topics page
		5-news_hub page
		6-categories page
		10-board page
		*/
		const reg = new RegExp("https:\\/\\/([a-z]+\\.|[a-z-]+\\.|)pinterest\\.(com|jp|at|ca|ch|co\\.uk|com\\.mx|de|dk|fr|nz|se|com\\.au|ie|ru)");

		if (document.location.pathname === "/")
		{
			this.whatPage = 1;
		} else if (url.match(new RegExp(reg.source + "/search", "i")))
		{
			this.whatPage = 2;
		} else if (url.match(new RegExp(reg.source + "/pin", "i")))
		{
			this.whatPage = 3;
		} else if (url.match(new RegExp(reg.source + "/topics", "i")))
		{
			this.whatPage = 4;
		} else if (url.match(new RegExp(reg.source + "/news_hub", "i")))
		{
			this.whatPage = 5;
		} else if (url.match(new RegExp(reg.source + "/categories", "i")))
		{
			this.whatPage = 6;
		} else
		{
			this.whatPage = 10;
		}
		return this.whatPage;
	}

	//UI SETTING "Full size"
	SetUpForPin()
	{
		var buttonDiv = document.createElement("div");
		var buttonButton = document.createElement("button");
		var buttonText = document.createTextNode("Full size");
		var parentDiv = document.querySelector("div[data-test-id='closeupActionBar'] div div") || document.querySelector("div[data-test-id='pinHeader']");

		if (typeof parentDiv === "undefined" || parentDiv === null)
		{
			console.log("div[data-test-id='closeupActionBar'] div div or div[data-test-id='pinHeader']:");
			return console.log(parentDiv);
		}

		buttonButton.appendChild(buttonText);
		buttonDiv.appendChild(buttonButton);
		parentDiv.appendChild(buttonDiv);
		$(buttonDiv).addClass("items-center");

		if (this.login === true) $(buttonDiv).attr("style", "display: flex;");

		$(buttonButton).addClass("SaveButton SaveButton--enabled SaveButton__background--enabled SaveButton__background");
		$(buttonButton).attr("style", "padding: 10px 14px; will-change: transform; margin-left: 8px;");

		if (this.login === false)
		{
			$(buttonButton).addClass("red active");
			$(buttonButton).attr("style", "background-color: rgb(230, 0, 35); padding: 10px 14px; will-change: transform; margin-left: 8px; border-radius: 8px; max-height: inherit;");
		}
		$(buttonButton).attr("id", "myBtn");

		if (this.pFullSize)
		{
			$(buttonButton).addClass("ppTrue");
		}

		this.Core(buttonButton);
	}

	async Core(buttonButton)
	{
		if (!this.oldWay)
		{
			var regU = document.URL.match(/\/(\d+)\/|\/([A-Z].+\w+)\//);
			if (typeof regU === "undefined" || regU === null)
			{
				this.oldWay = true;
				return this.Core(buttonButton);
			}
			var id = regU[1];
			var arr = [];

			if (typeof id === "undefined")
				id = regU[2];
			else if (typeof id === "undefined") { this.oldWay = true; return this.Core(buttonButton); }

			var time = Date.now();

			var tld = window.location.origin.split('.').pop();
			if (window.location.origin.endsWith('.com.au') || window.location.origin.endsWith('.com.mx') || window.location.origin.endsWith('.co.uk'))
			{
				let a = window.location.origin.split('.');
				tld = a[a.length - 2] +"."+ a.pop();
			}
			if (main.debug) console.log(tld);

			var urlRec = "https://www.pinterest." + tld + "/resource/PinResource/get/?source_url=/pin/" + id + "/&data={%22options%22:{%22field_set_key%22:%22detailed%22,%22id%22:%22" + id + "%22},%22context%22:{}}&_=" + time;

			$.get(urlRec, async function (r)
			{
				if (r["resource_response"]["status"] === "success")
				{
					if (main.debug) console.log(r["resource_response"]["data"]);
					let pin = r["resource_response"]["data"];
					if (pin["is_video"] === false && pin["videos"] === null)
					{
						if (pin["carousel_data"] === null) 
						{
							arr.push(pin["images"]["orig"]["url"]);
							main.SetEventButton(buttonButton, arr);
							if (main.pFullSize)
							{
								main.ShowFullSize(pin["images"]["orig"]["url"]);
							}
							return $(buttonButton).attr("title", "" + pin["images"]["orig"]["width"] + "px x " + pin["images"]["orig"]["height"] + "px");
						} else
						{
							/*let urlF = await GetFullSizeURL(query);

							if (typeof urlF === "undefined" || urlF === null)
							{
								console.error("image full url:");
								return console.error(urlF);
							}

							SetEventButton(buttonButton, urlF);

							if (pFullSize)
							{
								//ChangeSource(urlF, query);
								ShowFullSize(urlF[0]);
							}*/
						}
					} else
					{
						return console.log("VIDEO!!!");
					}

				} else
				{
					main.oldWay = true;
					console.log(r);
					return main.Core(buttonButton);
				}
			}, "json")
				.fail(function (e)
				{
					main.oldWay = true;
					console.log(e);
					return main.Core(buttonButton);
				});

		} else
		{
			//TODO NEED BETTER SELECTION!
			//query = document.querySelectorAll("a[rel] img[alt]");
			var query = $("article").find("img");

			if (typeof query === "undefined" || query === null || query.length === 0)
				query = $("div.closeupLegoContainer").find("a:first").find("img");

			if (main.debug) console.log(query);

			if (typeof query === "undefined" || query === null || query.length === 0)
			{
				console.log("query:");
				return console.log(query);
			}

			let urlF = await this.GetFullSizeURL(query);

			if (typeof urlF === "undefined" || urlF === null)
			{
				console.log("image full url:");
				return console.log(urlF);
			}

			this.SetEventButton(buttonButton, urlF);

			if (this.pFullSize)
			{
				this.ShowFullSize(urlF[0]);
			}
		}
	}

	//Hide popup after scrolling
	HidePopup()
	{
		if (this.login)
			return;

		setTimeout(function ()
		{
			let button = $(" button[aria-label='close']");
			if (button.length >= 1)
				$(button).click();

			var popup = $(" div[data-test-id='giftWrap']:parent");
			if (main.debug)
			{
				console.log(popup);
				console.log(button);
			}
			$(popup).attr("style", "display:none;");
		}, this.deltaTime);
	}

	async SetEventButton(btn, url)
	{
		$(btn).on('mousedown', async function (e)
		{
			if ((e.which === 3))
			{
				if (main.pFullSize)
				{
					GM.setValue("ppFullSize", false);
					$(btn).removeClass("ppTrue");
					let obj = {
						debug: main.debug,
						pFullSize: await GM.getValue("ppFullSize")
					}
					main.setValues = obj;
				} else
				{
					GM.setValue("ppFullSize", true);
					$(btn).addClass("ppTrue");
					let obj = {
						debug: main.debug,
						pFullSize: await GM.getValue("ppFullSize")
					}
					main.setValues = obj;
				}
				console.log("right");
			}
			if ((e.which === 1))
			{
				if (main.fullSize)
				{
					main.ChangeTagsBack();
				} else
				{
					main.ShowFullSize(url[0]);
				}
				console.log("left");
			}
			if ((e.which === 2))
			{
				GM.openInTab(url[0]);
				console.log("middle");
			}
			e.preventDefault();
		});
	}

	ShowFullSize(url)
	{
		let img;

		var queryCloseup = $("main[data-test-id='unauthPinPage']").find("div[data-test-id='pin']:first");

		if (typeof queryCloseup === "undefined" || queryCloseup === null || queryCloseup.length === 0)
			queryCloseup = $("div.Closeup");

		var querycontainCloseup = $("div.containCloseup");

		if (typeof querycontainCloseup === "undefined" || querycontainCloseup === null || querycontainCloseup.length === 0)
			querycontainCloseup = $("div[data-test-id='pinHeader']");

		if ($("#pp_divFullSize").length === 0)
		{
			const div = $("<div id=pp_divFullSize></div>").html("");
			queryCloseup.prepend(div);
		}

		var querypp_divFullSize = $("#pp_divFullSize");

		if ($("#pp_img").attr('src') === url)
		{
			querycontainCloseup.css("padding-top", url.height + 100);
			querypp_divFullSize.show(500);
			return this.fullSize = true;
		}

		if ($("#pp_img").length !== 0)
		{
			$("#pp_img").attr('src', url);
			img = $("#pp_img");
		} else
		{
			img = $("<img id=pp_img src='" + url + "'></img>");
		}

		var queryImg = $(img);
		var maxWidth = queryCloseup.css("width");

		if (typeof maxWidth === "undefined" || maxWidth === null)
			return console.log("Max width error:" + maxWidth);

		querypp_divFullSize.prepend(img);

		querypp_divFullSize.hide();

		queryImg.css("width", url.width);
		queryImg.css("height", url.height);
		queryImg.css("max-width", maxWidth);

		querycontainCloseup.css("padding-top", url.height + 100);
		querypp_divFullSize.show(500);

		this.fullSize = true;
	}

	async GetFullSizeURL(img)
	{
		if (typeof img === "undefined" || img === null)
		{
			return console.log("image url not found:" + img);
		}

		var arr = [];

		for (let i = 0; i < img.length; i++)
		{
			let src = $(img)[i].currentSrc;
			let oldSrc = src;
			let endUrl = new RegExp(src.slice(src.length - 3));

			if (this.debug) console.log(endUrl);

			src = src.replace(/[0-9]+x/, "originals");

			if (this.debug) console.log(src);

			await new Promise(function (resolve)
			{
				$.get(src, function ()
				{
					resolve(arr.push(src));
				})
					.fail(function ()
					{
						src = src.replace(endUrl, "png");
						$.get(src, function ()
						{
							resolve(arr.push(src));
						})
							.fail(function ()
							{
								src = src.replace(/png/, "gif");
								$.get(src, function ()
								{
									resolve(arr.push(src));
								})
									.fail(function ()
									{
										src = src.replace(/gif/, "webp");
										$.get(src, function ()
										{
											resolve(arr.push(src));
										})
											.fail(function ()
											{
												if (main.debug) alert("this try diferent url = " + oldSrc);
												resolve(arr.push(oldSrc));
											});
									});
							});
					});
			});
		}
		return arr;
	}

	ChangeTagsBack()
	{
		$("div.containCloseup").css("padding-top", 0);
		$("#pp_divFullSize").hide(500);
		this.fullSize = false;
	}

	//Handler for url
	UrlHandler()
	{
		this.oldHash = window.location.pathname;
		this.Check;

		var that = this;
		var detect = function ()
		{
			if (that.oldHash !== window.location.pathname)
			{
				that.oldHash = window.location.pathname;
				setTimeout(function () { main.SwitchPage(); }, main.deltaTime);
			}
		};
		this.Check = setInterval(function () { detect(); }, 200);
	}
}

var main = new Main(false, false);

/**
* ENUM, BECAUSE WHY NOT ¯\_(ツ)_/¯
* SEE FUNCTION GetPage()
*/
var Page;
(function (Page)
{
	Page[Page["ErrorNothing"] = 0] = "ErrorNothing";
	Page[Page["front"] = 1] = "front";
	Page[Page["search"] = 2] = "search";
	Page[Page["pin"] = 3] = "pin";
	Page[Page["topics"] = 4] = "topics";
	Page[Page["news_hub"] = 5] = "news_hub";
	Page[Page["categories"] = 6] = "categories";
	Page[Page["ErrorNothing2"] = 7] = "ErrorNothing2";
	Page[Page["ErrorNothing3"] = 8] = "ErrorNothing3";
	Page[Page["ErrorNothing4"] = 9] = "ErrorNothing4";
	Page[Page["board"] = 10] = "board";
})(Page || (Page = {}));

$(window).on("load", function ()
{
	console.log(main);
	main._Main();
});