Greasy Fork

Bundle Helper

Add tools for many bundle sites.

目前为 2017-05-15 提交的版本。查看 最新版本

// ==UserScript==
// @name        Bundle Helper
// @namespace   iFantz7E.BundleHelper
// @version     0.18
// @description Add tools for many bundle sites.
// @match      	*://cubicbundle.com/*
// @match      	*://dailyindiegame.com/*
// @match      	*://forums.steampowered.com/forums/showthread.php?*
// @match      	*://gogobundle.com/latest/bundles/*
// @match      	*://groupees.com/*
// @match      	*://otakumaker.com/*
// @match      	*://steamcommunity.com/*/home*
// @match      	*://steamcommunity.com/groups/*/announcements*
// @match      	*://steamcompanion.com/gifts/*
// @match      	*://steamground.com/*
// @match      	*://store.steampowered.com/account/notinterested/*
// @match      	*://store.steampowered.com/app/*
// @match      	*://store.steampowered.com/widget/*
// @match      	*://whosgamingnow.net/*
// @match      	*://www.bunchkeys.com/*
// @match      	*://www.bundlekings.com/*
// @match      	*://www.bundlestars.com/*/bundle/*
// @match      	*://www.bundlestars.com/*/promotions/*
// @match      	*://www.dailyindiegame.com/*
// @match      	*://www.gamebundle.com/*
// @match      	*://www.hrkgame.com/*
// @match      	*://www.humblebundle.com/*
// @match      	*://www.indiegala.com/*
// @match      	*://www.orlygift.com/*
// @match      	*://www.otakumaker.com/*
// @match      	*://www.reddit.com/r/*/comments/*
// @match      	*://www.superduperbundle.com/*
// @match      	*://www.sgtools.info/*
// @run-at		document-start
// @grant       GM_addStyle
// @grant       GM_xmlhttpRequest
// @connect     store.steampowered.com
// @connect     www.hrkgame.com
// @connect     www.bundlestars.com
// @connect     www.steamgifts.com
// @icon      	https://store.steampowered.com/favicon.ico
// @copyright	2016, 7-elephant
// ==/UserScript==

//// Connect to store.steampowered.com to get owner info
//// Connect to www.hrkgame.com and www.bundlestars.com to get Steam ID of each products
//// Connect to www.steamgifts.com to get bundle threads

(function ()
{	
	"use strict";
	// jshint multistr:true
	
function attachOnLoad(callback)
{
	window.addEventListener("load", function (e) 
	{
		callback();
	});
}

function attachOnReady(callback) 
{
	document.addEventListener("DOMContentLoaded", function (e) 
	{
		callback();
	});
}

function insertBeforeElement(newNode, referenceNode) 
{
	referenceNode.parentNode.insertBefore(newNode, referenceNode);
}

function insertAfterElement(newNode, referenceNode) 
{
	referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
}

function reload()
{
	var curHref = window.location.href;
	var posHashtag = curHref.indexOf("#");
	if (posHashtag > -1)
	{
		window.location = curHref.substr(0, posHashtag);
	}
	else
	{
		window.location = curHref;
	}
}

function getQueryByName(name, url)
{
	if (url == null)
	{
		url = location == null ? "" : location.search;
	}
	name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
	var regex = new RegExp("[\\?&]" + name + "=([^&#]*)");
	var results = regex.exec(url);
	var retVal = "";
	if (results != null)
	{
		retVal = results[1].replace(/\+/g, " ");
		try
		{
			retVal = decodeURIComponent(retVal);
		}
		catch (ex)
		{
			console.error("getQueryByName", ex.message);
		}
	}
	return retVal;
}

function clickToSelect(ele)
{
	if (ele != null)
	{
		var range = document.createRange();
		range.setStartBefore(ele.firstChild);
		range.setEndAfter(ele.lastChild);

		var sel = window.getSelection();
		sel.removeAllRanges();
		sel.addRange(range);
	}
}

function normalizeArray(arr)
{
	arr = arr.filter(function(elem, index, self) 
	{
		return index == self.indexOf(elem);
	});
	return arr;
}

function randNum(min, max)
{
	return Math.round(Math.random() * (max - min) + min);
}

function markOwned(query, markOwnedCallback)
{		
	var rgxId = /[0-9]{3,}/g;
	var rgxApp = /:\/\/((store\.steampowered|steamcommunity)\.com\/app|cdn.akamai.steamstatic.com\/steam\/apps)\/[0-9]+/i;
	var rgxSub = /:\/\/store\.steampowered\.com\/sub\/[0-9]+/i;
	
	GM_xmlhttpRequest(
	{
		method: "GET",
		url: "https://store.steampowered.com/dynamicstore/userdata/?t=" + randNum(1000, 9999),
		onload: function(response) 
		{
			var dataRes = JSON.parse(response.responseText);
			
			var countOwned = [0, 0];
			var countAll = [0, 0];
			
			if (typeof dataRes["rgOwnedApps"] !== "undefined"
				&& typeof dataRes["rgOwnedPackages"] !== "undefined"
				&& typeof dataRes["rgIgnoredApps"] !== "undefined")
			{
				var eleApps = document.querySelectorAll(query);
				for (var i = 0; i < eleApps.length; i++)
				{
					var attrHref = eleApps[i].getAttribute("href") || eleApps[i].getAttribute("src");
					var ids = attrHref.match(rgxId);
					if (ids != null)
					{
						var valId = parseInt(ids[0]);
							
						if (rgxApp.test(attrHref))
						{
							if (dataRes["rgOwnedApps"].indexOf(valId) > -1)
							{
								markOwnedCallback(eleApps[i]);
								countOwned[0]++;
							}
							else
							{
								console.log("App: not owned - http://store.steampowered.com/app/" + valId + "/");
							}
							countAll[0]++;
						}
						else if (rgxSub.test(attrHref))
						{								
							if (dataRes["rgOwnedPackages"].indexOf(valId) > -1)
							{
								markOwnedCallback(eleApps[i]);
								countOwned[1]++;
							}
							else
							{
								console.log("Sub: not owned - http://store.steampowered.com/sub/" + valId + "/");
							}
							countAll[1]++;
						}
					}
				}
				
			}
			
			var diff = countAll[0] - countOwned[0];
			console.log("App: " + countOwned[0] + "/" + countAll[0] + (diff > 10 ? " Diff: " + diff : ""));				
			console.log("Sub: " + countOwned[1] + "/" + countAll[1]);
			
		} // End onload
	});
}

function markOwned_old(query, getLabelCallback)
{
	var apps = [];
	
	var eleApps = document.querySelectorAll(query);
	
	for (var i = 0; i < eleApps.length; i++)
	{
		var app = /[0-9]+/.exec(eleApps[i].getAttribute("href"));
		if (app != null)
		{
			apps.push(app[0]);
		}
	}
	
	apps = apps.filter(function(elem, index, self) 
	{
		return index == self.indexOf(elem);
	});
	
	console.log("Apps: " + apps.length);
	var appAll = apps.join(",");
	
	GM_xmlhttpRequest(
	{
		method: "GET",
		headers: 
		{
			"Cache-Control": "max-age=0"
		},
		url: "https://store.steampowered.com/api/appuserdetails/?appids=" + appAll,
		onload: function(response) 
		{
			var dataRes = JSON.parse(response.responseText);
			
			var countOwned = 0;
			
			var eleApps = document.querySelectorAll(query);
			for (var i = 0; i < eleApps.length; i++)
			{
				var appUrl = eleApps[i].getAttribute("href");
				if (appUrl.indexOf("http://store.steampowered.com/app/") > -1)
				{
					var app = /[0-9]+/.exec(appUrl);
					if (app != null)
					{
						if (typeof dataRes[app] !== "undefined")
						{
							if (dataRes[app].success)
							{
								if (dataRes[app].data.is_owned)
								{
									var eleLabel = getLabelCallback(eleApps[i]);
									eleLabel.classList.add("bh_owned");
									countOwned++;
								}
								else
								{
									console.log("App: not owned - http://store.steampowered.com/app/" + app + "/");
								}
							}
							else
							{
								console.log("App: not success - https://steamdb.info/app/" + app + "/");
							}
						}
					}
				}
			}
			
			console.log("Apps: owned - " + countOwned);
			
		} // End onload
	});
}

function main()
{
	// #8BC349
	// #6EA028
	// #2ECC71
	// #92B300
	
	GM_addStyle(
		"   .bh_button { "
		+ "	  border-radius: 2px; border: medium none; padding: 10px; display: inline-block; "
		+ "   cursor: pointer; background: #67C1F5 none repeat scroll 0% 0%; "
		+ "   width: 120px; text-align: center; } "
		+ " .bh_button a { "
		+ "   text-decoration: none !important; color: #FFF !important; "
		+ "   padding: 0px 2px; } "
		+ " .bh_button:hover a { "
		+ "   color: #0079BF !important; } "
		+ " .bh_button, .bh_button a { "
		+ "   font-family: Verdana; font-size: 12px; "
		+ "   line-height: 16px; } "
		+ " .bh_owned { background-color: #7CA156 !important; "
		+ "   transition: background 500ms ease 0s; } "
		+ " #bh_markOwned { "
		+ "   position: fixed; right: 20px; bottom: 20px; z-index:3; } "
		+ " #bh_OpenLib { "
		+ "   position: fixed; right: 20px; bottom: 65px; z-index:3; } "
	);
	
	var url = document.documentURI;
	
	if (url.indexOf("hrkgame.com") > -1)
	{
		if (window !== window.parent)
			return;
		
		GM_addStyle(
			"   .bh_owned { background-color: #97BA22 !important; } "
			+ " #bh_markOwned { bottom: 40px !important; } "
		);
		
		if (url.indexOf("/randomkeyshop/make-bundle") > -1)
		{
			// Add load button
			{
				var divButton = document.createElement("div");
				divButton.classList.add("bh_button");
				divButton.id = "bh_loadAll";
				divButton.setAttribute("style", "bottom: 86px;");
				divButton.setAttribute("onclick", " \
					this.firstElementChild.textContent = \"Loading...\"; \
					window.scrollTo(0,document.body.scrollHeight); \
					var countHidden = 5; \
					var idx = setInterval(function(ele) \
					{ \
						var eleLoad = document.querySelector(\"#loader-icon\"); \
						if (eleLoad) \
						{ \
							window.scrollTo(0,document.body.scrollHeight); \
							if (eleLoad.style.display == \"none\") \
							{ \
								countHidden--; \
							} \
							else \
							{ \
								countHidden = 5; \
							} \
						} \
						else \
						{ \
							countHidden--; \
						} \
						if (countHidden < 0) \
						{ \
							clearInterval(idx); \
							ele.style.display=\"none\"; \
							var eleRes = document.querySelector(\"#result\"); \
							if (eleRes) \
							{ \
								eleRes.scrollIntoView(true); \
								window.scrollBy(0, -80); \
							} \
						} \
					}, 500, this); \
					return false; \
				");
				divButton.innerHTML = "<a onclick='return false;'>Load All</a>";
				document.body.appendChild(divButton);
			}
			
			// Add mark button
			{
				var divButton = document.createElement("div");
				divButton.classList.add("bh_button");
				divButton.id = "bh_markOwned";
				
				var eleA = document.createElement("a");
				eleA.setAttribute("onclick", "return false;");
				eleA.textContent = "Mark Owned";
				
				divButton.appendChild(eleA);
				document.body.appendChild(divButton);				
				
				divButton.addEventListener("click", function()
				{						
					GM_xmlhttpRequest(
					{
						method: "GET",
						url: "https://store.steampowered.com/dynamicstore/userdata/?t=" + randNum(1000, 9999),
						onload: function(response) 
						{
							var dataResSteam = JSON.parse(response.responseText);
							
							if (typeof dataResSteam["rgOwnedApps"] == "undefined"
								|| dataResSteam["rgOwnedApps"].length == 0)
							{
								console.log("not logged in");
							}	
							else if (typeof dataResSteam["rgOwnedApps"] !== "undefined"
								&& typeof dataResSteam["rgOwnedPackages"] !== "undefined"
								&& typeof dataResSteam["rgIgnoredApps"] !== "undefined")
							{
								var parser = new DOMParser();
								var rgxId = /[0-9]+/;
								var rgxApp = /:\/\/store\.steampowered\.com\/app\/[0-9]+/i;
								var rgxSub = /:\/\/store\.steampowered\.com\/sub\/[0-9]+/i;
								
								var elesProduct = document.querySelectorAll("#result .content:not(.bh_owned)");
								
								var productCur = 0;
								var tmId = setInterval(function()
								{
									if (productCur >= elesProduct.length)
									{
										clearInterval(tmId);
									}
									else
									{
										var dataHref = elesProduct[productCur].firstElementChild.getAttribute("data-href");
										if (dataHref != null)
										{
											var fullHref = "https://www.hrkgame.com" + dataHref + "/";
											elesProduct[productCur].setAttribute("bh_href", fullHref);
											
											GM_xmlhttpRequest(
											{
												method: "GET",
												url: fullHref,
												onload: function(response) 
												{
													var isOwned = false;
													
													var dataRes = parser.parseFromString(response.responseText, "text/html");
													
													var eleA = dataRes.querySelector(".storeside a.item[href*='store.steampowered.com/']");
													if (eleA != null)
													{
														var attrHref = eleA.href;
														var id = rgxId.exec(attrHref);
														if (id != null)
														{
															var valId = parseInt(id);
																
															if (rgxApp.test(attrHref))
															{
																if (dataResSteam["rgOwnedApps"].indexOf(valId) > -1)
																{
																	isOwned = true;
																}
																else
																{
																	console.log("App: not owned - http://store.steampowered.com/app/" + id + "/");
																}
															}
															else if (rgxSub.test(attrHref))
															{								
																if (dataResSteam["rgOwnedPackages"].indexOf(valId) > -1)
																{
																	isOwned = true;
																}
																else
																{
																	console.log("Sub: not owned - http://store.steampowered.com/sub/" + id + "/");
																}
															}
															
															if (isOwned)
															{
																for (var i = 0; i < elesProduct.length; i++)
																{
																	if (elesProduct[i].getAttribute("bh_href") == response.finalUrl)
																	{
																		elesProduct[i].classList.add("bh_owned");
																		break;
																	}
																}
															}
														}
													}
													else
													{
														console.log("Info: not found - " + response.finalUrl);
													}
													
												} // End onload
											});
										}
									}
									productCur++
								}, 200);
							}
							
						} // End onload
					});
				});
			}
		}
		else if (url.indexOf("/library") > -1)
		{				
			var clientScript = ' \
				confirm = function() \
				{ \
					return true; \
				}; \
			';

			var eleClientScript = document.createElement("script");
			eleClientScript.innerHTML = clientScript;
			document.head.appendChild(eleClientScript);
		}
	}
	else if (url.indexOf("bundlestars.com") > -1)
	{
		GM_addStyle(
			//" .bh_owned { background-color: #A7CC00 !important; } "
			" .bh_owned { background-color: #D0FE00 !important; } "
			+ " .bh_owned:hover { background-color: #BBE500 !important; } "
			+ " .bh_owned * { color: #444 !important; } "
			+ " .bh_owned .was, .bh_owned .was * { color: #777 !important; } "
			+ " .bh_owned .hide-checkbox + label span { color: #DDD !important; } "
			+ " .bh_owned .hide-checkbox:checked + label span { color: #D0FE00 !important; } "
			+ " #launcher { bottom: 100px !important; } "
		);
		
		if (url.indexOf("/bundle/") > -1)
		{
			// Add mark button
			{
				var divButton = document.createElement("div");
				divButton.classList.add("bh_button");
				divButton.id = "bh_markOwned";
				
				var eleA = document.createElement("a");
				eleA.setAttribute("onclick", "return false;");
				eleA.textContent = "Mark Owned";
				
				divButton.appendChild(eleA);
				document.body.appendChild(divButton);
				
				divButton.addEventListener("click", function()
				{
					markOwned(".bundle-accordian a.btn-bundle-more[href*='store.steampowered.com/']", function(ele)
					{
						ele.parentElement.parentElement
							.parentElement.parentElement.parentElement
							.parentElement.parentElement.parentElement
							.parentElement.firstElementChild
							.classList.add("bh_owned");
					});
				});
			}
		}
		else if (url.indexOf("/promotions/") > -1)
		{
			// Add mark button
			{
				var divButton = document.createElement("div");
				divButton.classList.add("bh_button");
				divButton.id = "bh_markOwned";
				
				var eleA = document.createElement("a");
				eleA.setAttribute("onclick", "return false;");
				eleA.textContent = "Mark Owned";
				
				divButton.appendChild(eleA);
				document.body.appendChild(divButton);
				
				divButton.param_promo = url.substr(url.indexOf("/promotions/") + 12)
					.replace(/\?.*/, "").replace(/#.*/, "");
				eleA.param_promo = divButton.param_promo;
				
				divButton.addEventListener("click", function(e)
				{						
					var promo = e.target.param_promo;
					
					GM_xmlhttpRequest(
					{
						method: "GET",
						url: "https://store.steampowered.com/dynamicstore/userdata/?t=" + randNum(1000, 9999),
						onload: function(response) 
						{
							var dataResSteam = JSON.parse(response.responseText);
							
							if (typeof dataResSteam["rgOwnedApps"] == "undefined"
								|| dataResSteam["rgOwnedApps"].length == 0)
							{
								console.log("not logged in");
							}	
							else if (typeof dataResSteam["rgOwnedApps"] !== "undefined"
								&& typeof dataResSteam["rgOwnedPackages"] !== "undefined"
								&& typeof dataResSteam["rgIgnoredApps"] !== "undefined")
							{										
								var elesProduct = document.querySelectorAll(".bs-card-body:not(.bh_owned)");
								for (var i = 0; i < elesProduct.length; i++)
								{
									var sref = elesProduct[i].firstElementChild.getAttribute("ui-sref");
									if (sref != null)
									{
										elesProduct[i].setAttribute("bh_slug"
											, sref.replace("base.game({ slug: '", "")
												.replace("base.dlc({ slug: '", "")
												.replace("' })", ""));
									}
								}
								
								GM_xmlhttpRequest(
								{
									method: "GET",
									url: "https://www.bundlestars.com/api/promotions/" + promo,
									onload: function(response) 
									{
										var dataRes = JSON.parse(response.responseText);
										
										var slugs = [];
										
										var i = dataRes.length - 1;
										//for (var i = 0; i < dataRes.length; i++)
										{
											
											for (var j = 0; j < dataRes[i].products.length; j++)
											{
												if (dataRes[i].products[j].drm.steam)
												{
													slugs.push(dataRes[i].products[j].slug);
												}
											}
										}
										
										slugs = normalizeArray(slugs);
										
										var slugCur = 0;
										var tmId = setInterval(function()
										{
											if (slugCur >= slugs.length)
											{
												clearInterval(tmId);
											}
											else
											{
												GM_xmlhttpRequest(
												{
													method: "GET",
													url: "https://www.bundlestars.com/api/products/" + slugs[slugCur],
													onload: function(response) 
													{
														var isOwned = false;
														
														var dataRes = JSON.parse(response.responseText);
														
														if (!dataRes.steam.sub)
														{
															if (dataResSteam["rgOwnedApps"].indexOf(dataRes.steam.id) > -1)
															{
																isOwned = true;
															}
															else
															{
																console.log("App: not owned - http://store.steampowered.com/app/" + dataRes.steam.id + "/ - " + dataRes.slug);
															}
														}
														else
														{
															if (dataResSteam["rgOwnedPackages"].indexOf(dataRes.steam.id) > -1)
															{
																isOwned = true;
															}
															else
															{
																console.log("Sub: not owned - http://store.steampowered.com/sub/" + dataRes.steam.id + "/ - " + dataRes.slug);
															}
														}
														
														if (isOwned)
														{
															for (var i = 0; i < elesProduct.length; i++)
															{
																if (elesProduct[i].getAttribute("bh_slug") == dataRes.slug)
																{
																	elesProduct[i].classList.add("bh_owned");
																	break;
																}
															}
														}
														
													} // End onload
												});
											}
											slugCur++;
										}, 200);
										
									} // End onload
								});
							
							}
							
						} // End onload
					});
				});
			}
		}
	}
	else if (url.indexOf("reddit.com") > -1)
	{
		GM_addStyle(
			"   .bh_owned , .md .bh_owned code { background-color: #DFF0D8 !important; } "
			+ " li > .bh_owned { padding: 0px 2px 0px 2px; } "
		);
		
		// Add mark button
		{
			var divButton = document.createElement("div");
			divButton.classList.add("bh_button");
			divButton.id = "bh_markOwned";
			
			var eleA = document.createElement("a");
			eleA.setAttribute("onclick", "return false;");
			eleA.textContent = "Mark Owned";
			
			divButton.appendChild(eleA);
			//document.body.appendChild(divButton);
			
			divButton.addEventListener("click", function()
			{
				markOwned("td > a[href*='store.steampowered.com/']", function(ele)
				{
					ele.parentElement.parentElement.classList.add("bh_owned");
				});					
			});
		}
		
		setTimeout(function()
		{
			markOwned("td > a[href*='store.steampowered.com/']", function(ele)
			{
				ele.parentElement.parentElement.classList.add("bh_owned");
			});
			
			markOwned("li > a[href*='store.steampowered.com/']", function(ele)
			{
				ele.classList.add("bh_owned");
			});	
		}, 1000);
	}
	else if (url.indexOf("groupees.com") > -1)
	{
		GM_addStyle(
			"   .bh_owned { background-color: #DFF0D8 !important; } "
			+ " #subscribe-form { display: none; } "
			+ " input[name='search'] { position: fixed; z-index: 1099; left: 18%; top: 16px; } "
			+ " button[role='show3dKeyModal'] { position: fixed; z-index: 1099; left: 72%; top: 16px; } "
			+ " .cancel-spin { position: fixed !important; z-index: 1099 !important; left: 39.5% !important; top: 22px !important; } "
			+ " .bh_owned_dark { background-color: rgba(140, 197, 63, 0.6) !important; } "	
		);
		/*
		var a = document.querySelector("input[name='search']");
		var b = document.querySelector("#subscribe-form");
		b.parentElement.insertBefore(a,b);
		b.parentElement.removeChild(b);
		*/
		// Add mark button
		{
			var divButton = document.createElement("div");
			divButton.classList.add("bh_button");
			divButton.id = "bh_markOwned";
			
			var eleA = document.createElement("a");
			eleA.setAttribute("onclick", "return false;");
			eleA.textContent = "Mark Owned";
			
			divButton.appendChild(eleA);
			document.body.appendChild(divButton);				
			
			divButton.addEventListener("click", function()
			{
				var apps = [];
				
				var eleApps = document.querySelectorAll(".bundle > .products .info .description a[href*='store.steampowered.com/app/']"
					+ ", .expanded .product-info a[href*='store.steampowered.com/app/']"
					+ ", .product-details.hidden .external-links a[href*='store.steampowered.com/app/']");
				console.log("Apps: " + eleApps.length);
				
				for (var i = 0; i < eleApps.length; i++)
				{
					var app = /[0-9]+/.exec(eleApps[i].getAttribute("href"));
					if (app != null)
					{
						apps.push(app[0]);
					}
				}
				
				apps = apps.filter(function(elem, index, self) 
				{
					return index == self.indexOf(elem);
				});
				
				var appAll = apps.join(",");
				
				GM_xmlhttpRequest(
				{
					method: "GET",
					headers: 
					{
						"Cache-Control": "max-age=0"
					},
					url: "https://store.steampowered.com/api/appuserdetails/?appids=" + appAll,
					onload: function(response) 
					{
						var dataRes = JSON.parse(response.responseText);
						
						var countOwned = 0;
						
						var elePurchases = null;
						var elePrds = document.querySelectorAll(".bundle > .products .product h3"
							+ ", .expanded .details, .product-info");
						var eleApps = document.querySelectorAll(".bundle > .products .info"
							+ ", .expanded .details, .product-details.hidden");
						for (var i = 0; i < eleApps.length; i++)
						{								
							var eleApp = eleApps[i].querySelector(".description a[href*='store.steampowered.com/app/']"
								+ ", .product-info a[href*='store.steampowered.com/app/']"
								+ ", .external-links a[href*='store.steampowered.com/app/']");
							if (eleApp != null)
							{
								var app = /[0-9]+/.exec(eleApp.getAttribute("href"));
								if (app != null)
								{
									if (typeof dataRes[app] !== "undefined")
									{
										if (dataRes[app].success)
										{
											if (dataRes[app].data.is_owned)
											{
												var eleLabel = elePrds[i];
												if (eleLabel.classList.contains("product-info"))
												{
													eleLabel.classList.add("bh_owned_dark");
													
													// Mark game in build bundles
													{
														var eleName = eleLabel.querySelector("h4");
														if (eleName)
														{
															var name = eleName.textContent.trim();
															
															if (elePurchases == null)
															{
																elePurchases = document.querySelectorAll(".purchase-products > .bundle-product > .input > label");
															}
															
															if (elePurchases != null)
															{
																for (var j = 0; j < elePurchases.length; j++)
																{
																	if (elePurchases[j].textContent.trim() == name)
																	{
																		elePurchases[j].parentElement.parentElement.classList.add("bh_owned_dark");
																	}
																}
															}
														}
													}
													
												}
												else
												{
													eleLabel.classList.add("bh_owned");
												}
												countOwned++;
											}
											else
											{
												console.log("App: not owned - http://store.steampowered.com/app/" + app);
											}
										}
										else
										{
											console.log("App: not success - http://store.steampowered.com/app/" + app);
										}
									}
								}
							}
						}
						
						console.log("Apps: owned - " + countOwned);
						
					} // End onload
				});
				
			});
		}
	}
	else if (url.indexOf("indiegala.com") > -1)
	{
		GM_addStyle(
			"   .bh_owned { background-color: rgba(125, 174, 45, 0.9) !important; } "
			+ " .bh_owned .add-info-button-cont .left, .bh_owned .add-info-button-cont .palette-background-2 { "
			+ "   background-color: #7DAE2D !important; } "
			+ " .bh_owned .add-info-button-cont .right .inner-info, .bh_owned .add-info-button-cont .right .palette-border-2 { "
			+ "   border-color: #7DAE2D !important; } "
			+ " .bh_owned.medium-game .game-cover-medium { border: 3px solid #7DAE2D; background-color: rgba(125, 174, 45, 0.4); } "
			+ " .bh_owned.game-data-cont { background-color: #76AD1C !important; } "
			+ " .bundle-item-trading-cards-cont span { opacity: 0.7; } "
			+ " .span-title .title_game, .span-title .title_drm, .span-title .title_music { "
			+ "   line-height: 43px !important; margin: 10px 0px 10px 15px !important; "
			+ "   padding-left: 10px !important; border-radius: 3px !important; } "
		);
		
		// Auto reload when error
		{
			setTimeout(function()
			{
				if (document.title == "500 Server Error")
				{
					console.log("Autorefresh: 500 Server Error");
					setTimeout(function()
					{
							reload();
					}, 5000);
				}
			}, 10000);
		}
		
		// Insert email to bundle section
		{
			var countRetryEmail = 10;
			var tmRetryEmail = setInterval(function()
			{
				var eleEmail = document.querySelector(".account-email");
				var eleInput = document.querySelector(".email-input");
				if (eleEmail && eleInput)
				{
					var email = eleEmail.textContent.trim();
					if (email != "")
					{
						eleInput.value = email;
						clearInterval(tmRetryEmail);
					}
				}
				
				if (countRetryEmail < 0)
				{
					clearInterval(tmRetryEmail);
				}
				countRetryEmail--;
			}, 3000);
		}
		
		// Add mark button
		if (url.indexOf("/store/product/") < 0)
		{
			var divButton = document.createElement("div");
			divButton.classList.add("bh_button");
			divButton.id = "bh_markOwned";
			
			var eleA = document.createElement("a");
			eleA.setAttribute("onclick", "return false;");
			eleA.textContent = "Mark Owned";
			
			divButton.appendChild(eleA);
			document.body.appendChild(divButton);
			
			divButton.addEventListener("click", function()
			{
				var rgxId = /[0-9]{3,}/g;
				var rgxApp = /:\/\/((store\.steampowered\.com|steamcommunity\.com)\/app|www.indiegala.com\/store\/product\/[^\/]+)\/[0-9]+/i;
				var rgxSub = /:\/\/(store\.steampowered\.com|steamcommunity\.com)\/sub\/[0-9]+/i;
				var rgxInvalidApp = /:\/\/store\.steampowered\.com\/[0-9]+\//i;
				
				var eleApps = document.querySelectorAll("a[href*='store.steampowered.com/']");
				for (var i = 0; i < eleApps.length; i++)
				{
					var attrHref = eleApps[i].getAttribute("href");
					if (rgxInvalidApp.test(attrHref))
					{
						eleApps[i].setAttribute("href", attrHref.replace("store.steampowered.com/", "store.steampowered.com/app/"));
					}
				}

				GM_xmlhttpRequest(
				{
					method: "GET",
					url: "https://store.steampowered.com/dynamicstore/userdata/?t=" + randNum(1000, 9999),
					onload: function(response) 
					{
						var dataRes = JSON.parse(response.responseText);
						
						var countOwned = 0;
						
						if (typeof dataRes["rgOwnedApps"] !== "undefined"
							&& typeof dataRes["rgOwnedPackages"] !== "undefined"
							&& typeof dataRes["rgIgnoredApps"] !== "undefined")
						{
							var elePrds = document.querySelectorAll(
								".bundle-item-link, .in .in .in .game-steam-url"
								+ ", #this_your_gift .game-steam-url");
							var eleApps = document.querySelectorAll(
								".game-opened-switcher a[href*='store.steampowered.com/'].game-steam-url"
								+ ", .game-opened-switcher a[href*='steamcommunity.com/'].game-steam-url"
								+ ", .in .in .in .game-steam-url"
								+ ", #this_your_gift .game-steam-url"
								+ ", .game-cover-medium[href^='/store/product/']"
								+ ", #game_list_div .game-data-cont a[href^='/store/product/']"
								+ ", .search-page-store .game-data-cont a[href^='/store/product/']");
							
							var eleTitle = document.querySelector("#title-p");
							if (eleTitle && eleTitle.textContent.trim() === "Indiegala gift")
							{
								elePrds = document.querySelectorAll(
									"#steam-key-games .game-steam-url");
								eleApps = document.querySelectorAll(
									"#steam-key-games .game-steam-url");
							}
							
								
							for (var i = 0; i < eleApps.length; i++)
							{
								var attrHref = eleApps[i].href;
								var ids = attrHref.match(rgxId);
								if (ids != null)
								{
									var valId = parseInt(ids[ids.length - 1]);
									
									var eleLabel = null;
									
									if (eleApps[i].classList.contains("game-cover-medium"))
									{
										eleLabel = eleApps[i].parentElement;
									}
									else if (eleApps[i].parentElement.parentElement.classList.contains("game-data-cont"))
									{
										eleLabel = eleApps[i].parentElement.parentElement;
									}
									else
									{
										eleLabel = elePrds[i].parentElement;
									}
									
									if (rgxApp.test(attrHref))
									{
										if (dataRes["rgOwnedApps"].indexOf(valId) > -1)
										{
											eleLabel.classList.add("bh_owned");
											countOwned++;
										}
										else
										{
											console.log("App: not owned - http://store.steampowered.com/app/" + valId);
										}
									}
									else if (rgxSub.test(attrHref))
									{								
										if (dataRes["rgOwnedPackages"].indexOf(valId) > -1)
										{
											eleLabel.classList.add("bh_owned");
											countOwned++;
										}
										else
										{
											console.log("Sub: not owned - http://store.steampowered.com/sub/" + valId);
										}
									}
								}
							}
							
							console.log("Apps: owned - " + countOwned);
						}
					} // End onload
				});
				
			});
		}
		
		// Change title
		{
			var countRetryTitle = 10;
			var tmRetryTitle = setInterval(function()
			{
				var elesPrice = document.querySelectorAll(".bundle-claim-phrase");
				for (var i = elesPrice.length - 1; i > -1; i--)
				{
					var elePrice = elesPrice[i].querySelector("span");
					if (elePrice)
					{
						var price = elePrice.textContent.trim();
						if (price.indexOf("$") == 0)
						{
							document.title = price + " " + document.title;
							clearInterval(tmRetryTitle);
							break;
						}
					}
				}
				
				if (countRetryTitle < 0)
				{
					clearInterval(tmRetryTitle);
				}
				countRetryTitle--;
			}, 3000);
		}
		
		// Load library
		if (url.indexOf("/profile") > -1)
		{
			var clientScript = " \
				function openBundleLibrary() \
				{ \
					$.ajax({ \
						type: 'GET', \
						data: { user_id : '" + getQueryByName("user_id") + "' }, \
						url: '/ajaxprofile_sale_tab', \
						dataType: 'json', \
						context: $( '#profile_bundle_section .accordion-toggle' ), \
						 \
						beforeSend: function(){ \
							console.log('Start: open bundle library' ); \
							openBundleLibraryAjaxSemaphore = false; \
							$('.spinner', $( '#profile_bundle_section .accordion-toggle' ) ).remove(); \
							$( '#profile_bundle_section .accordion-toggle' ).append(\" <span class='spinner'><i class='fa fa-spinner fa-spin'></i></span>\"); \
						}, \
						success: function(data){ \
							console.log('Success: open bundle library' ); \
							$( '#collapseBundles .panel-body' ).html( data['html'] ); \
							setTimeout(function() \
							{ \
								$('#profile_bundle_section .accordion-toggle:not([aria-expanded=\"true\"])').click(); \
							}, 500); \
						}, \
						error: function(){ \
							console.log('Error: open bundle library' ); \
							setTimeout(openBundleLibrary, 500); \
						}, \
						complete: function(){ \
							openBundleLibraryAjaxSemaphore = false; \
							$('.spinner', $( '#profile_bundle_section .accordion-toggle' ) ).remove(); \
						}, \
					}); \
				} \
			";

			var eleClientScript = document.createElement("script");
			eleClientScript.innerHTML = clientScript;
			document.head.appendChild(eleClientScript);
			
			var divButton = document.createElement("div");
			divButton.classList.add("bh_button");
			divButton.id = "bh_OpenLib";
			divButton.setAttribute("onclick", "openBundleLibrary()");
			
			var eleA = document.createElement("a");
			eleA.setAttribute("onclick", "return false;");
			eleA.textContent = "Open Library";
			
			divButton.appendChild(eleA);
			document.body.appendChild(divButton);
		}
		
		if (url.indexOf("/successpay") > -1)
		{
			setTimeout(function()
			{
				var eleBtn = document.querySelector("#faang.fa-angle-down");
				if (eleBtn)
				{
					eleBtn.click();
				}
			}, 5000);
		}
	}
	else if (url.indexOf("orlygift.com") > -1)
	{
		if (window !== window.parent)
			return;
		
		// Add mark button
		{
			var divButton = document.createElement("div");
			divButton.classList.add("bh_button");
			divButton.id = "bh_markOwned";
			
			var eleA = document.createElement("a");
			eleA.textContent = "Mark Owned";
			
			divButton.appendChild(eleA);
			document.body.appendChild(divButton);				
			
			divButton.addEventListener("click", function()
			{
				var apps = [];
				
				var eleApps = document.querySelectorAll("div[id^='game-detail-'] a.btn-primary[href^='http://store.steampowered.com/app/']");
				console.log("Apps: " + eleApps.length);
				
				for (var i = 0; i < eleApps.length; i++)
				{
					var app = /[0-9]+/.exec(eleApps[i].getAttribute("href"));
					if (app != null)
					{
						apps.push(app[0]);
					}
				}
				
				apps = apps.filter(function(elem, index, self) 
				{
					return index == self.indexOf(elem);
				});
				
				var appAll = apps.join(",");
				
				GM_xmlhttpRequest(
				{
					method: "GET",
					headers: 
					{
						"Cache-Control": "max-age=0"
					},
					url: "https://store.steampowered.com/api/appuserdetails/?appids=" + appAll,
					onload: function(response) 
					{
						var dataRes = JSON.parse(response.responseText);
						
						var countOwned = 0;
						
						var elePrds = document.querySelectorAll(".box-game");
						var eleApps = document.querySelectorAll("div[id^='game-detail-']");
						for (var i = 0; i < eleApps.length; i++)
						{
							var eleApp = eleApps[i].querySelector("a.btn-primary[href^='http://store.steampowered.com/app/']");
							if (eleApp != null)
							{
								var app = /[0-9]+/.exec(eleApp.getAttribute("href"));
								if (app != null)
								{
									if (typeof dataRes[app] !== "undefined")
									{
										if (dataRes[app].success)
										{
											if (dataRes[app].data.is_owned)
											{
												var eleLabel = elePrds[i];
												eleLabel.classList.add("bh_owned");
												countOwned++;
											}
											else
											{
												console.log("App: not owned - " + app);
											}
										}
										else
										{
											console.log("App: not success - " + app);
										}
									}
								}
							}
						}
						
						console.log("Apps: owned - " + countOwned);
						
					} // End onload
				});
				
			});
		}
	}
	else if (url.indexOf("cubicbundle.com") > -1)
	{
		GM_addStyle(
			"   .bh_owned { background-color: #91BA07 !important; } "
		);
		// Add mark button
		{
			var divButton = document.createElement("div");
			divButton.classList.add("bh_button");
			divButton.id = "bh_markOwned";
			
			var eleA = document.createElement("a");
			eleA.setAttribute("onclick", "return false;");
			eleA.textContent = "Mark Owned";
			
			divButton.appendChild(eleA);
			document.body.appendChild(divButton);
			
			divButton.addEventListener("click", function()
			{
				markOwned(".price a[href*='store.steampowered.com/']", function(ele)
				{
					ele.parentElement.parentElement.parentElement.classList.add("bh_owned");
				});						
			});
		}
	}
	else if (url.indexOf("dailyindiegame.com") > -1)
	{			
		GM_addStyle(
			"   .bh_owned, .bh_owned a, .bh_owned a:not(:visited) .DIG2content { color: #202020 !important; } "
		);

		// Add mark button
		{
			var divButton = document.createElement("div");
			divButton.classList.add("bh_button");
			divButton.id = "bh_markOwned";
			
			var eleA = document.createElement("a");
			eleA.setAttribute("onclick", "return false;");
			eleA.textContent = "Mark Owned";
			
			divButton.appendChild(eleA);
			document.body.appendChild(divButton);				
			
			divButton.addEventListener("click", function()
			{
				if (document.querySelectorAll(".DIG-content a[href*='store.steampowered.com/']").length > 0)
				{
					markOwned(".DIG-content a[href*='store.steampowered.com/']", function(ele)
					{
						ele.parentElement
							.parentElement.parentElement
							.parentElement.parentElement
							.classList.add("bh_owned");
					});
				}
				else
				{
					markOwned(".DIG2content a[href*='store.steampowered.com/']", function(ele)
					{
						ele.parentElement
							.parentElement
							.classList.add("bh_owned");
					});
				}
			});
		}
	}
	else if (url.indexOf("bundlekings.com") > -1)
	{			
		// Add mark button
		{
			var divButton = document.createElement("div");
			divButton.classList.add("bh_button");
			divButton.id = "bh_markOwned";
			
			var eleA = document.createElement("a");
			eleA.setAttribute("onclick", "return false;");
			eleA.textContent = "Mark Owned";
			
			divButton.appendChild(eleA);
			document.body.appendChild(divButton);
			
			divButton.addEventListener("click", function()
			{
				markOwned(".content-wrap a[href*='store.steampowered.com/']", function(ele)
				{
					ele.parentElement.parentElement.parentElement.classList.add("bh_owned");
				});					
			});
		}
	}
	else if (url.indexOf("otakumaker.com") > -1)
	{			
		GM_addStyle(
			"   .bh_owned { background-color: #91BA07 !important; } "
		);
		
		// Add mark button
		{
			var divButton = document.createElement("div");
			divButton.classList.add("bh_button");
			divButton.id = "bh_markOwned";
			
			var eleA = document.createElement("a");
			eleA.setAttribute("onclick", "return false;");
			eleA.textContent = "Mark Owned";
			
			divButton.appendChild(eleA);
			document.body.appendChild(divButton);
			
			divButton.addEventListener("click", function()
			{
				markOwned(".gantry-width-spacer a[href*='store.steampowered.com/']", function(ele)
				{
					ele.parentElement.parentElement.classList.add("bh_owned");
				});					
			});
		}
	}
	else if (url.indexOf("gogobundle.com") > -1)
	{			
		GM_addStyle(
			"   .bh_owned { background-color: #91BA07 !important; } "
		);
		
		// Add mark button
		{
			var divButton = document.createElement("div");
			divButton.classList.add("bh_button");
			divButton.id = "bh_markOwned";
			
			var eleA = document.createElement("a");
			eleA.setAttribute("onclick", "return false;");
			eleA.textContent = "Mark Owned";
			
			divButton.appendChild(eleA);
			document.body.appendChild(divButton);
			
			divButton.addEventListener("click", function()
			{
				markOwned(".g-block > .g-block > a[href*='store.steampowered.com/']", function(ele)
				{
					ele.parentElement.parentElement.classList.add("bh_owned");
				});					
			});
		}
	}
	else if (url.indexOf("superduperbundle.com") > -1)
	{			
		// Add mark button
		{
			var divButton = document.createElement("div");
			divButton.classList.add("bh_button");
			divButton.id = "bh_markOwned";
			
			var eleA = document.createElement("a");
			eleA.setAttribute("onclick", "return false;");
			eleA.textContent = "Mark Owned";
			
			divButton.appendChild(eleA);
			document.body.appendChild(divButton);
			
			divButton.addEventListener("click", function()
			{
				markOwned("#gameslist a[href*='store.steampowered.com/']", function(ele)
				{
					ele.parentElement.parentElement.classList.add("bh_owned");
				});					
			});
		}
	}
	else if (url.indexOf("gamebundle.com") > -1)
	{				
		GM_addStyle(
			"   .bh_owned { background-color: #A0CC41 !important; border-bottom: 45px solid rgba(233, 233, 233, 0.5); } "
			+ " .bh_owned .activebundle_game_bundle_debut_title { background-color: #A0CC41 !important; } "
		);

		// Add mark button
		{
			var divButton = document.createElement("div");
			divButton.classList.add("bh_button");
			divButton.id = "bh_markOwned";
			
			var eleA = document.createElement("a");
			eleA.setAttribute("onclick", "return false;");
			eleA.textContent = "Mark Owned";
			
			divButton.appendChild(eleA);
			document.body.appendChild(divButton);
			
			divButton.addEventListener("click", function()
			{
				markOwned(".activebundle_game_section_full a[href*='store.steampowered.com/']", function(ele)
				{
					ele.parentElement.classList.add("bh_owned");
				});					
			});
		}
	}
	else if (url.indexOf("humblebundle.com") > -1)
	{
		GM_addStyle(
			"   .game-box img { max-height: 180px !important; max-width: 130px !important; } "
		);
		
		var strBta = "Beat the Average of ";
		
		var elesPrice = document.querySelectorAll(".hr-payment-tier-heading-text");
		for (var i = 0; i < elesPrice.length; i++)
		{
			var priceRaw = elesPrice[i].textContent.trim();
			if (priceRaw.indexOf(strBta) > -1)
			{
				var price = priceRaw.replace(strBta, "");
				document.title = price + " " + document.title;
				break;
			}
		}
		
		var eleSold = document.querySelector(".heading-bundles-sold .mini-digit-holder");
		if (eleSold != null) 
		{
			var sold = eleSold.getAttribute("data-initial-value") || "";
			eleSold.parentElement.parentElement.setAttribute("title", sold);
		}
		
		var countRetrySold = 10;
		var tmRetrySold = setInterval(function()
		{
			var sold = "";
			var elesSold = document.querySelectorAll(".mini-digit-holder .top-cutter .heading-num");
			for (var i = 0; i < elesSold.length; i++)
			{
				sold = sold + "" + elesSold[i].textContent.trim();
			}
			
			if (sold !== "")
			{
				clearInterval(tmRetrySold);
					
				var eleCount = document.querySelector(".hr-tagline-bundles-sold");
				if (eleCount)
				{
					eleCount.textContent += " (" + sold.replace(/^0+/, "") + ")";
				}
			}
			
			if (countRetrySold < 0)
			{
				clearInterval(tmRetrySold);
			}
			countRetrySold--;
		}, 1000);			

		if (url.indexOf("/downloads") > -1)
		{
			GM_addStyle(
				"   #steam-tab .redeem-instructions, #steam-tab .recommend-this-game { display: none; } "
			);
		
			setTimeout(function()
			{
				var elesKey = document.querySelectorAll(".sr-redeemed-bubble");
				for (var i = 0; i < elesKey.length; i++)
				{
					elesKey[i].addEventListener("click", function (e)
					{
						var ele = e.target;
						clickToSelect(ele);
					});
				}
			}, 3000);
		}
	}
	else if (url.indexOf("steamcompanion.com") > -1)
	{			
		GM_addStyle(
			"   .bh_owned.banner { margin-bottom: 5px !important; margin-top: 35px !important; "
			+ "   padding-bottom: 15px !important; padding-top: 15px !important; } "
			+ " .bh_owned.giveaway-links { opacity: 0.75; } "
		);
		
		markOwned("#hero a[href*='store.steampowered.com/']", function(ele)
		{
			ele.classList.add("bh_owned");
		});
		
		// Mark
		{
			var query = ".giveaway-links img[src^='https://steamcdn-a.akamaihd.net/steam/apps/']";
			var getLabelCallback = function(ele)
			{
				return ele.parentElement.parentElement.parentElement;
			};
			
			var apps = [];
			
			var eleApps = document.querySelectorAll(query);
			
			for (var i = 0; i < eleApps.length; i++)
			{
				var app = /[0-9]+/.exec(eleApps[i].getAttribute("src"));
				if (app != null)
				{
					apps.push(app[0]);
				}
			}
			
			apps = apps.filter(function(elem, index, self) 
			{
				return index == self.indexOf(elem);
			});
			
			console.log("Apps: " + apps.length);
			var appAll = apps.join(",");
			
			GM_xmlhttpRequest(
			{
				method: "GET",
				headers: 
				{
					"Cache-Control": "max-age=0"
				},
				url: "https://store.steampowered.com/api/appuserdetails/?appids=" + appAll,
				onload: function(response) 
				{
					var dataRes = JSON.parse(response.responseText);
					
					var countOwned = 0;
					
					var eleApps = document.querySelectorAll(query);
					for (var i = 0; i < eleApps.length; i++)
					{
						var appUrl = eleApps[i].getAttribute("src");
						if (appUrl.indexOf("https://steamcdn-a.akamaihd.net/steam/apps/") > -1)
						{
							var app = /[0-9]+/.exec(appUrl);
							if (app != null)
							{
								if (typeof dataRes[app] !== "undefined")
								{
									if (dataRes[app].success)
									{
										if (dataRes[app].data.is_owned)
										{
											var eleLabel = getLabelCallback(eleApps[i]);
											eleLabel.classList.add("bh_owned");
											countOwned++;
										}
										else
										{
											//console.log("App: not owned - http://store.steampowered.com/app/" + app + "/");
										}
									}
									else
									{
										//console.log("App: not success - https://steamdb.info/app/" + app + "/");
									}
								}
							}
						}
					}
					
					console.log("Apps: owned - " + countOwned);
					
				} // End onload
			});
		}
	}
	else if (url.indexOf("store.steampowered.com") > -1)
	{
		if (url.indexOf("/widget/") > -1) 
		{
			GM_addStyle(
				"   .bh_owned { background-color: transparent !important; } "
				+ " .bh_owned a { color: #71A034 !important; }"
			);
		
			markOwned(".main_text a[href*='store.steampowered.com/']", function(ele)
			{
				ele.parentElement.classList.add("bh_owned");
			});	
		}
		else if (url.indexOf("/app/") > -1) 
		{
			GM_addStyle(
				"   .bh_owned { "
				+ "   background-color: #6D8C1A !important; "
				+ "   padding: 0px 2px 0px 2px; "
				+ " } "
			);
			
			markOwned(".glance_details p > a[href*='store.steampowered.com/']"
				+ ", .game_area_dlc_bubble  a[href*='store.steampowered.com/']", 
				function(ele)
				{
					ele.classList.add("bh_owned");
				});	
		}
		else if (url.indexOf("/notinterested/") > -1) 
		{
			GM_addStyle(
				"   .bh_owned { "
				+ "   background-color: #6D8C1A !important; "
				+ "   padding: 5px 100px 5px 5px !important; "
				+ "   margin-left: -5px; margin-right: 50px; "
				+ " } "
			);
			
			markOwned(".ignoredapps > a[href*='store.steampowered.com/']", function(ele)
			{
				ele.classList.add("bh_owned");
			});	
		}
	}
	else if (url.indexOf("steamcommunity.com") > -1)
	{
		GM_addStyle(
			"   .bh_owned { background-color: #71A034 !important; "
			+ "   padding: 0px 2px 0px 2px; } "
			+ " .bh_owned.blotter_userstatus_game { padding: 0px; border-color: #71A034; } "
		);
		
		if (url.indexOf("/home") > -1)
		{
			var querySteamHome = ".blotter_gamepurchase_details a[href*='store.steampowered.com/']:not(.bh_owned) "
				+ ", .blotter_author_block a[href*='store.steampowered.com/']:not(.bh_owned) "
				+ ", .blotter_author_block a[href*='steamcommunity.com/app/']:not(.bh_owned) "
				+ ", .blotter_daily_rollup_line a[href*='steamcommunity.com/app/']:not(.bh_owned) ";
			markOwned(querySteamHome, function(ele)
			{
				if (ele.classList.contains("blotter_userstats_game"))
				{
					ele.parentElement.classList.add("bh_owned");
				}
				else
				{
					ele.classList.add("bh_owned");
				}
			});
			
			var targetObMark = document.getElementById("blotter_content"); 
			if (targetObMark)
			{
				var tmObMark = -1;
				var obMark = new MutationObserver(function(mutations) 
				{ 
					mutations.forEach(function(mutation) 
					{ 
						clearTimeout(tmObMark);
						tmObMark = setTimeout(function(querySteamHome)
						{							
							markOwned(querySteamHome, function(ele)
							{
								if (!ele.classList.contains("blotter_userstats_game"))
								{
									ele.classList.add("bh_owned");
								}
							});
				
						}, 100, querySteamHome);
					});
				});

				var configObMark = { childList: true }; 
				obMark.observe(targetObMark, configObMark);
			}
		}
		else if (url.indexOf("/announcements") > -1)
		{
			markOwned(".announcement_body a[href*='store.steampowered.com/']", function(ele)
			{
				ele.classList.add("bh_owned");
			});	
		}
	}
	else if (url.indexOf("forums.steampowered.com") > -1)
	{
		GM_addStyle(
			"   .bh_owned { background-color: #71A034 !important; "
			+ "   padding: 0px 2px 0px 2px;"
			+ " } "
		);
		
		markOwned("div[id^='post_message'] a[href*='store.steampowered.com/']", function(ele)
		{
			ele.classList.add("bh_owned");
		});
	}
	else if (url.indexOf("whosgamingnow.net") > -1)
	{
		if (url.indexOf("/discussion") > -1)
		{
			GM_addStyle(
				"   .bh_owned { "
				+ "   padding: 0px 2px 0px 2px;"
				+ " } "
			);
			
			markOwned(".MessageList a[href*='store.steampowered.com/']", function(ele)
			{
				ele.classList.add("bh_owned");
			});
		}
		else if (url.indexOf("/redeem") > -1)
		{
			GM_addStyle(
				"   .bh_owned { "
				+ "   border: 1px solid #FFF;"
				+ " } "
				+ " .bh_owned .BoxArt { "
				+ "   border: 0px !important;"
				+ " } "
			);
			
			markOwned(".GameInfo a[href*='store.steampowered.com/']", function(ele)
			{
				ele.parentElement.parentElement.parentElement.classList.add("bh_owned");
			});
		}
		else if (url.indexOf("/giveaway") > -1)
		{
			GM_addStyle(
				"   .bh_owned { "
				+ "   border: 5px solid #7CA156;"
				+ " } "
			);
			
			markOwned("img[src*='://cdn.akamai.steamstatic.com/steam/']", function(ele)
			{
				ele.classList.add("bh_owned");
			});
		}
	}
	else if (url.indexOf("steamground.com") > -1 && url.indexOf("/wholesale") > -1)
	{
		GM_addStyle(
			"   .bh_owned { background-color: #48B24B !important; } "
			+ " .bh_owned .wholesale-card_title { color: #373d41 !important; } "
			+ " .bh_steam { display: none; } "
		);
		
		var elesTitle = document.querySelectorAll(".wholesale-card_title");
		if (elesTitle.length > 0)
		{
			GM_xmlhttpRequest(
			{
				method: "GET",
				url: "https://www.steamgifts.com/discussion/iy081/steamground-wholesale-build-a-bundle",
				onload: function(response) 
				{					
					var data = response.responseText;
					var eleContainer = document.createElement("div");
					eleContainer.innerHTML = data;
					
					var eleComment = eleContainer.querySelector(".comment__description");
					if (eleComment)
					{							
						var elesGame = eleComment.querySelectorAll("table td:nth-child(1) a[href*='store.steampowered.com/']");
						if (elesGame.length > 0)
						{
							var arrTitle = [];
							for (var i = 0; i < elesTitle.length; i++)
							{
								arrTitle.push(elesTitle[i].textContent.trim());
							}
							
							for (var i = 0; i < elesGame.length; i++)
							{
								var isMatch = false;
								var game = elesGame[i].textContent.trim().toLowerCase();
								for (var j = 0; j < elesTitle.length; j++)
								{
									var title = elesTitle[j].textContent.trim().toLowerCase();
									if (game === title
										|| (title.indexOf("|") > -1 && game === title.replace("|", ":"))
										|| (game === "ball of light" && title === "ball of light (journey)")
										|| (game === "its your last chance in new school" && title === "it is yоur last chance in new schооl")
										|| (game === "shake your money simulator 2016" && title === "shake your money simulator")
										|| (game === "spakoyno: back to the ussr 2.0" && title === "spakoyno back to the ussr 2.0")
										|| (game === "or" && title === "or!"))
									{
										isMatch = true;
										
										arrTitle = arrTitle.filter(function(value) 
										{ 
											return value !== elesTitle[j].textContent.trim() 
										});
									}
									
									if (isMatch)
									{
										var eleA = document.createElement("a");
										eleA.classList.add("bh_steam");
										eleA.href = elesGame[i].href;
										elesTitle[j].parentElement.parentElement.appendChild(eleA);
										
										break;
									}
								}
								if (!isMatch)
								{
									console.log("Not match: " + elesGame[i].href + " " + elesGame[i].textContent);
								}
							}

							if (arrTitle.length > 0)
							{
								console.log("Not match: " + arrTitle.length);
								for (var i = 0; i < arrTitle.length; i++)
								{
									console.log("Not match: " + arrTitle[i]);
								}
							}
		
							markOwned(".wholesale-card > a[href*='store.steampowered.com/']", function(ele)
							{
								ele.parentElement.classList.add("bh_owned");
							});	
						}
					}
					
				} // End onload
			});
		}
	}
	else if (url.indexOf("bunchkeys.com") > -1)
	{
		GM_addStyle(
			"   .bh_owned { border: #B5D12E 3px solid !important; "
			+ "   margin-left: -3px; margin-top: -3px; } "
		);

		// Add mark button
		{
			var divButton = document.createElement("div");
			divButton.classList.add("bh_button");
			divButton.id = "bh_markOwned";
			
			var eleA = document.createElement("a");
			eleA.setAttribute("onclick", "return false;");
			eleA.textContent = "Mark Owned";
			
			divButton.appendChild(eleA);
			document.body.appendChild(divButton);
			
			divButton.addEventListener("click", function()
			{
				markOwned("a[href*='store.steampowered.com/']", function(ele)
				{
					ele.parentElement.classList.add("bh_owned");
				});					
			});
		}
	}
	else if (url.indexOf("sgtools.info") > -1)
	{
		GM_addStyle(
			"   .bh_owned { background-color: #71A034 !important; } "
		);
		if (url.indexOf("/lastbundled") > -1)
		{
			markOwned("#content > div > table > tbody > tr > td > a[href*='store.steampowered.com/']", function(ele)
			{
				ele.parentElement.parentElement.classList.add("bh_owned");
			});
		}
		else if (url.indexOf("/deals") > -1)
		{			
			markOwned(".deal_game_image > img[src*='cdn.akamai.steamstatic.com/steam/']", function(ele)
			{
				ele.parentElement.classList.add("bh_owned");
			});
		}
		else if (url.indexOf("/whitelisted") > -1)
		{
			markOwned(".cmGame > a[href*='store.steampowered.com/']", function(ele)
			{
				ele.parentElement.classList.add("bh_owned");
			});
		}
	}
}

attachOnReady(main);
	
})();

// End