Airdates.tv enhancer

Control how many past weeks you want to see and many other enhancements

当前为 2018-01-21 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name        Airdates.tv enhancer
// @namespace   V@no
// @author      V@no
// @description Control how many past weeks you want to see and many other enhancements
// @include     http://www.airdates.tv/*
// @include     https://www.airdates.tv/*
// @include     https://disqus.com/embed/comments/*
// @icon        data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAEiElEQVRYw+2VW4hVVRjHf+uyz97nnLkcHWfGuWYzDlKUhUrUgynkQxREFJFEDwbzFkXQg0I9hIRF9BDRk1AyigkhouJDBuEEPlcQNdqo1cnRzozpzDnOuezL+no4czVnqIfBl/m/7L2+tde3/vv7/uu/YBWruMdQCweXRkff2Ltv36elUun3MAzFswnabiCq5qiGIX1NIT3uD8TzEJXDmo2kMbAOLvddoTg5RXNDI1YPEIce63vuo1fyrPcm0RmfX0cr97/wylvv9PX3HJjd0y4kkP8zv+nMmTPs379/wyObN3PzVhbPOwDuCF0JHPd38YF7n6zVoL7G6PeYXgebLz7MwTcPEmoIbUwUDpIOrjCQUbyrPuQrPUhLWKWv6xAvvjzauXDPRQQ8L0U6SLPrqV1s2bplJrphbv43OoEnmAbg5lx8ujVkW+nxBZkEShEAEWsp0kYRaG3dSENjsqgF+s6OCI4oDgGo1cA5mZuNFndsPkl89zhAgpn/QZP8e+3ioSBOEGFFIFLPvyQBESGKImSFGLjE4RK3XAUgTpKVI+ASXLKMBhQgzq0YgThOcLJcC2YrwMoQiFxM7OKlCcyqT5z7z0n/D1yckMTLtGD2v1fqFERxjHPLiHC29yulgcQlJHeIcJETzm5sbf3p+4sTqKW0oZYjPD8XhjFRsowG7l6B+Xe1hBMqdWd8fo1esKZSrRLFiwksqoCZcc3duzWtbVCtQHNTlkwWrgjsKWeRqfo3xwPDS00Q3IDCQxkeKIPT4BzktgXYXyAPfPSZZeh1iBLY97ZiZMQtTSAM6xfI2NgPjI3lAB+4ARgwlhGmILmEQ0BfpjloobdsqepmLiQ/gWhIhFxvO6nSbcbLFcKWv4ECnlEYc51ytW9pAr6fVu1tnQTpvWSzoJQQR60kbhOec5w332L0lyilyakcvXQhHjRGf/FYzw6sZ/FTPrq7B2+gn3QqxeFPjnLo4yGMMdRqNZ57/lX/rgREZODw0NBgc64B319DHIVESUzKC3BRREiCHwd0JB2AQitNiSLaGCpGoVvWzOnRK04ixVukrYfVlkqlgmiFiHDhwsigiBxVSg3PERCR7PC5c+dPnT6dEhHa2zsoThVRClK+T6VSwRiDUgqjTf1WAxJxWAXKOZwDqzVaa5qbmylXyigB63mEYUhDJsP18QInTp4kt3btKRF5UCk1pkRkIJ/Pf372m7PbNYrJyUmqtSrWWJwTtNaghFq1hvU80kGKWhSThDFWK0ARR1VwjiCVwg8CfC/AGEu2sZHYJXjaooW6B/iWQqHAkzt3/vzo1i171HfDw18cO3bstfGJCYLAB6kfq7ppODzPm7mmQ5I4RmlDd1cHjQ0NlCshTamA2AiV8m0mCuOgFJ71SZwj5XmEtRqJc2htUAqM1oS1Globnn72mUN2YmLiyLVr1/J9/f391tpGpVUkru4FSlG3TgFtNL6f4urVcX788Xs6OteTL0zT5sXcLJUJgR3bt+OcULpd8tpza4rdPd3XnYjVWiMzfqGVIpPJpC5dvOiM0SdYxSruNf4Bbv4W546hynoAAAAASUVORK5CYII=
// @license     MIT
// @version     1.27.1
// @run-at      document-start
// @grant       none
// ==/UserScript==

//tab = 2 spaces


let log = console.log;

let adeName = "Airdates.tv enhancer",
		adeVersion = "n/a",
		force = false,
		enginesDefault = [],
		_engines = [],
		_hidden = ls("hidden") || [],
		loo = 1000,
		_enginesList = [];


try
{
	adeName = GM_info.script.name;
	adeVersion = GM_info.script.version;
}catch(e){};
function ls(id, data)
{
	let r;
	if (typeof(data) == "undefined")
	{
		r = localStorage.getItem(id);
		try
		{
			r = JSON.parse(r);
		}catch(e){}
	}
	else
	{
		try
		{
			r = localStorage.setItem(id, JSON.stringify(data));
		}
		catch(e){log(e);}
	}
	return r;
}
function cs(id, data)
{
	let r;
	if (typeof(data) == "undefined")
	{
		r = readCookie(id);
		try
		{
			r = JSON.parse(r);
		}catch(e){}
	}
	else
	{
		try
		{
			r = createCookie(id, JSON.stringify(data));
		}
		catch(e){}
	}
	return r;
}
cs.list = ["s","n"];
cs.listLegacy = {
	sh: "showHidden",
	sn: "showNew",
	sr: "showReturn",
	cm: "collapseMulti",
	w: "weeks",
	wa: "enableWatched",
	middleClick: "middleClick"
};
function multiline(func)
{
	func = func.toString();
	return func.slice(func.indexOf("/*") + 2, func.lastIndexOf("*/")).split("*//*").join("*/").replace(/[\n\t]*/g, "");
}

let enginesHide = ls("enginesHide") || [];
let Settings = {
	SORT_NAME: 0,
	SORT_COLOR: 1,
	inited: false,
	box: null,
	prefs: {},
	prefsDef: {
		enableWatched: 0,
		shortTitle: 0,
		shortTitleExpand: 1,
//		animateExpand: 0,
		showHidden: 0,
		collapseMulti: 0,
		showNew: 0,
		showReturn: 0,
		middleClick: [],
		weeks: 0,
		sortBy: 0,
	},
	pref: function(id, val)
	{
		if (typeof(val) == "undefined")
			return typeof(this.prefs[id]) == "undefined" ? null : this.prefs[id];

		this.prefs[id] = val;
		this.save();
	},
	init: function()
	{
		if (this.inited)
			return;

		this.prefs = ls("settings") || this.prefsDef;
		for(i in this.prefsDef)
		{
			if (!(i in this.prefs))
				this.prefs[i] = this.prefsDef[i];
		}
		let c = cs("wa"),
				s = false;

		if (c !== null)
		{
			this.prefs.enableWatched = c ? 1 : 0;
			eraseCookie("wa");
			s = true;
		}
		c = cs("showhidden");
		if (c !== null)
		{
			this.prefs.showHidden = c ? 1 : 0;
			eraseCookie("showhidden");
			s = true;
		}
		c = cs("sh");
		if (c !== null)
		{
			this.prefs.showHidden = c ? 1 : 0;
			eraseCookie("sh");
			s = true;
		}

		c = cs("cm");
		if (c !== null)
		{
			this.prefs.collapseMulti = c ? 1 : 0;
			eraseCookie("cm");
			s = true;
		}

		c = cs("middleClick");
		if (c !== null)
		{
			this.prefs.middleClick = c ? c : [];
			eraseCookie("middleClick");
			s = true;
		}

		//splitting New/Returning into two separate filters
		c = cs("sn");
		if (c === null && this.pref("showNew") === null)
		{
			let n = cs("n") ? 1 : 0;
			this.prefs.showNew = n;
			this.prefs.showReturn = n;
		}
		else if (c !== null)
		{
			this.prefs.showNew = c;
			eraseCookie("sn");
			s = true;
		}

		c = cs("sr");
		if (c !== null)
		{
			this.prefs.showReturn = c;
			eraseCookie("sr");
			s = true;
		}

		c = cs("w");
		if (c !== null)
		{
			this.prefs.weeks = c;
			eraseCookie("w");
			s = true;
		}

		if (s)
			this.save();

		this.create();
	},
	create: function(callback)
	{
		if (Settings.box)
			return callback ? callback() : true;

		let html = multiline(function(){/*
<div id="settings-popup">
	<div id="settings-popup-content">
		<div class="header">
			<div class="back">
				<svg viewBox="0 0 24 24">
					<path d="M20,11V13H8L13.5,18.5L12.08,19.92L4.16,12L12.08,4.08L13.5,5.5L8,11H20Z" />
				</svg>
			</div>
			<h4>Options</h4>
			<div class="close">
				<svg viewBox="0 0 24 24">
					<path d="M19,3H16.3H7.7H5A2,2 0 0,0 3,5V7.7V16.4V19A2,2 0 0,0 5,21H7.7H16.4H19A2,2 0 0,0 21,19V16.3V7.7V5A2,2 0 0,0 19,3M15.6,17L12,13.4L8.4,17L7,15.6L10.6,12L7,8.4L8.4,7L12,10.6L15.6,7L17,8.4L13.4,12L17,15.6L15.6,17Z"></path>
				</svg>
				<svg viewBox="0 0 24 24">
					<path d="M19,3H5A2,2 0 0,0 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5A2,2 0 0,0 19,3M19,19H5V5H19V19M17,8.4L13.4,12L17,15.6L15.6,17L12,13.4L8.4,17L7,15.6L10.6,12L7,8.4L8.4,7L12,10.6L15.6,7L17,8.4Z"></path>
				</svg>
			</div>
		</div>
		<div class="content">
		</div>
	</div>
</div>
		*/});//html

		let popup = $(html).appendTo("body"),
				content = popup.find(".content"),
				a = document.createElement("a"),
				i = document.createElement("span"),
				span = document.createElement("div");

		content.toggleClass("settings", true);
		span.appendChild(i);
		span.appendChild(a);

		Settings.box = popup;
		popup.find(".back").click(function()
		{
			Settings.hide();
			setTimeout(function()
			{
				$("#account-overview").click();
			});
		});
		content.append(createCheckbox("enableWatched", "Enable watched", this.prefs.enableWatched ? true : false, this.callback, null, "pointer"));
		let opt = createCheckbox("shortTitle", "Truncate long titles", this.prefs.shortTitle ? true : false, this.callback, null, "pointer");
		opt.title = "Shorten titles to fit into single row.";
		content.append(opt);
		opt = createCheckbox("shortTitleExpand", "Auto expand truncated titles", this.prefs.shortTitleExpand ? true : false, this.callback, null, "pointer");
		opt.title = "Show full title when cursor over it. If disabled you still be able see full title in tooltip or when show is opened.";
		content.append(opt);
//		content.append(createCheckbox("animateExpand", "Animate during expanding", this.prefs.animateExpand ? true : false, this.callback, null, "pointer"));
		content.append('<div class="spacer"/>');

		a.href = "#";
		i.innerHTML = '<svg viewBox="0 0 24 24"><path d="M12,3A9,9 0 0,0 3,12H0L4,16L8,12H5A7,7 0 0,1 12,5A7,7 0 0,1 19,12A7,7 0 0,1 12,19C10.5,19 9.09,18.5 7.94,17.7L6.5,19.14C8.04,20.3 9.94,21 12,21A9,9 0 0,0 21,12A9,9 0 0,0 12,3M14,12A2,2 0 0,0 12,10A2,2 0 0,0 10,12A2,2 0 0,0 12,14A2,2 0 0,0 14,12Z" /></svg>';
		a.textContent = "Backup settings";
		span.title = "Backup all settings that also include links settings, watched and hidden shows lists, middle click selection.";
		let backup = function()
		{
			let cookies = {},
					str = "",
					obj = {
						version: adeVersion,
						settings: Settings.prefs
					};

			for(let i = 0; i < cs.list.length; i++)
			{
				let v = cs(cs.list[i]);
				if (v !== null)
				{
					cookies[cs.list[i]] = v;
				}
			}
			for(let i in cookies)
			{
				obj.cookies = cookies;
				break;
			}
			for(let i in _hidden)
			{
				obj.hidden = _hidden;
				break;
			}
			for(let i in watched._list)
			{
				obj.watched = watched._list;
				break;
			}
			for(let i in customLinks._list)
			{
				obj.customLinks = customLinks._list;
				break;
			}
			for(let i in enginesHide)
			{
				obj.enginesHide = enginesHide;
				break;
			}
			for(let i in enginesSort._list)
			{
				obj.enginesSort = enginesSort._list;
				break;
			}
			str = JSON.stringify(obj);

			return str;
		}
		a.addEventListener("click", function(e)
		{
			e.preventDefault();

			let str = backup();
			if (str)
					prompt( adeName + " Settings \nYou can save it in a normal textfile and/or restore it to another computer/browser.", str );
			else
					alert("Nothing to backup");
			return false;
		}, false);
		let d = a.cloneNode(true);


		d.addEventListener("click", function(e)
		{
			if (e.isTrigger)
				return;

			e.preventDefault();
			e.stopPropagation();

			let d = new Date(),
					date = d.getFullYear() + pad(d.getMonth()+1) + pad(d.getDate()) + pad(d.getHours()) + pad(d.getMinutes()) + pad(d.getSeconds());

			fileSave("Airdates.tv_enhancer_v" + adeVersion + "_settings_" + date + ".json", backup());
		}, false);
		d.textContent = "save to file";
		d.className = "file";
		span.appendChild(d);
		content.append(span);

		span = span.cloneNode(true);
		span.title = "Note, your watched and hidden shows list will stay intact, new shows will be added to it. Custom links will only overwrite existing with matched ID. Everything else will be overwritten";
		i = span.firstChild;
		a = i.nextSibling;
		d = span.lastChild;
		i.innerHTML = '<svg viewBox="0 0 24 24"><path d="M13,3A9,9 0 0,0 4,12H1L4.89,15.89L4.96,16.03L9,12H6A7,7 0 0,1 13,5A7,7 0 0,1 20,12A7,7 0 0,1 13,19C11.07,19 9.32,18.21 8.06,16.94L6.64,18.36C8.27,20 10.5,21 13,21A9,9 0 0,0 22,12A9,9 0 0,0 13,3M12,8V13L16.28,15.54L17,14.33L13.5,12.25V8H12Z" /></svg>';
		a.textContent = "Restore settings";
		function restore(str)
		{
			let reload = false,
					txt = "Error restoring settings";
			if(!str)
				return;

			let hiddenNum = 0,
					watchedNum = 0,
					settingsNum = 0,
					enginesNum = 0,
					engineHideNum = 0;

			let json = null;
			try
			{
				json = JSON.parse(str);
			}
			catch(e){}
			if (json)
			{
				if ("hidden" in json)
				{
					hiddenNum = json.hidden.length;
					for(let i = 0; i < hiddenNum; i++)
						showHide(parseInt(json.hidden[i]), 1);
				}
				if ("watched" in json)
				{
					for(let id in json.watched)
					{
						for(let i = 0; i < json.watched[id].length; i++)
						{
							let ep = json.watched[id][i];
							watched.add(id, ep);
							watchedNum++;
							$('div.entry[data-series-id="' + id + '"]').each(function(n, entry)
							{
								if (watched.title(entry) == ep)
									watched.update(entry, true);
							});
						}
					}
					watched.save(true);
				}
				if (!json.cookies)
					json.cookies = {};

				if ("settings" in json)
				{
					let save = false;
					for(let i in json.settings)
					{
						let val = json.settings[i];
						if (i in cs.listLegacy && !(i in Settings.prefsDef))
						{
							val = json.settings[i];
							i = cs.listLegacy[i];
						}

						if (!(i in Settings.prefsDef))
						{
							if (!(i in json.cookies) && cs.list.indexOf(i) != -1)
								json.cookies[i] = val;

							continue;
						}

						if (!command(i, val))
						{
							settingsNum++;
							Settings.prefs[i] = val;
							reload = true;
							save = true;
						}
					}
					if (save)
						Settings.save();
				}

				if ("cookies" in json)
				{
					for(let i in json.cookies)
					{
						if (cs.list.indexOf(i) == -1)
							continue;

						if (!command(i, json.cookies[i]))
						{
							settingsNum++;
							cs(i, json.cookies[i]);
							reload = true;
						}
					}
				}
				let enginesNew = [];
				if ("customLinks" in json)
				{
					let changed = false;
					for (i in json.customLinks)
					{
						enginesNum++;
						changed = reload = true;
						customLinks._list[i] = json.customLinks[i];
						enginesNew.push(json.customLinks[i]);
					}
					if (changed)
						ls("customLinks", customLinks._list);

				}
				if ("enginesHide" in json)
				{
					let changed = false;
					let list = [];
					for(let i = 0; i < json.enginesHide.length; i++)
					{
						if (enginesFind(json.enginesHide[i]) != -1 || enginesFind(json.enginesHide[i], enginesNew) != -1)
						{
							list[list.length] = json.enginesHide[i];
							changed = reload = true;
							engineHideNum++;
						}
					}
					enginesHide = list;
					if (changed)
						ls("enginesHide", enginesHide);
				}
				if ("enginesSort" in json)
				{
					let changed = false;
					enginesSort._list = [];
					for(let i = 0; i < json.enginesSort.length; i++)
					{
						if (enginesFind(json.enginesSort[i]) != -1 || enginesFind(json.enginesSort[i], enginesNew) != -1)
						{
							changed = reload = true;
							enginesSort._list.push(json.enginesSort[i]);
						}
					}
					if (changed)
						ls("enginesSort", enginesSort._list);
				}
				txt = settingsNum + " setting" + (settingsNum > 1 ? "s" : "") + " imported" + ((hiddenNum || watchedNum) ? " and marked " : "");
				if (hiddenNum)
					txt += hiddenNum + " show" + (hiddenNum > 1 ? "s" : "") + " as hidden";
				if (watchedNum)
					txt += (hiddenNum ? ", " : " ") + watchedNum + " as watched";
			}
			alert(txt);
			if (reload)
				window.location.reload();
		}
		a.addEventListener("click", function(e)
		{
			e.preventDefault();
			restore(prompt( "Please enter the " + adeName + " settings text" ));
		}, false);

		d.addEventListener("click", function(e)
		{
			e.preventDefault();
			e.stopPropagation();
			fileLoad(function(text)
			{
				restore(text);
			});
		}, false);
		d.textContent = "load from file";
		span.appendChild(d);
		content.append(span);


	},//Settings.create()

	callback: function(e, id, check)
	{
		Settings.prefs[id] = check ? 1 : 0;
		Settings.save();
	},

	save: function(f)
	{
		ls("settings", this.prefs);
	},

	show: function()
	{
		Settings.box.show();
	},

	hide: function()
	{
		Settings.box.hide();
	},
}//Settings

function fileLoad(callback, ext)
{
	let f = document.createElement("input");
	f.type = "file";
	if (typeof(ext) == "undefined")
		ext = ".json";

	if (ext)
		f.setAttribute("accept", ext);

	function readFile(e)
	{
		f.removeEventListener("change", readFile, false);
		let files = f.files;
		if (!f.files.length)
		{
			alert('Please select a file!');
			return;
		}
		let reader = new FileReader();

		reader.onloadend = function(evt)
		{
			if (evt.target.readyState == FileReader.DONE)
			{
				callback(evt.target.result);
			}
		};

		let blob = f.files[0].slice(0, f.files[0].size);
		reader.readAsBinaryString(blob);
	}
	f.addEventListener("change", readFile, false);
	f.click();
}

function fileSave(name, data, type)
{
	type = type ? type : 'text/json';
	let blob = new Blob([data], {type: type}),
			a = document.createElement("a"),
			d = new Date(),
			date = d.getFullYear() + pad(d.getMonth()+1) + pad(d.getDate()) + pad(d.getHours()) + pad(d.getMinutes()) + pad(d.getSeconds());

	a.download = name;
	a.href = window.URL.createObjectURL(blob);
	a.dataset.downloadurl = [type, a.download, a.href].join(':');
	document.body.appendChild(a);
	a.click();
	a.parentNode.removeChild(a);
}

function exportGetColors()
{
	let str = $.map(DB.savedColors,function(e,i){return i + "=" + e;}).join(";");
	return str.replace(/;?[0-9]+=#FFFFFF/i, "");
}

function pad(t)
{
	return "" + t < 10 ? "0" + t : t;
}

function enginesBackup()
{
	if (!enginesBackup.backup)
		enginesBackup.backup = window.engines;
}

function enginesRestore()
{
	if (enginesBackup.backup)
	{
		window.engines = enginesBackup.backup;
		enginesBackup.backup = null
	}
}

function enginesAdd(id)
{
	for(let i = 0; i < _engines.length; i++)
	{
		if (_engines[i].name == id || _engines[i].host == id)
			return;
	}
	for(let i = 0; i < engines.length; i++)
	{
		if (engines[i].name == id || engines[i].host == id)
		{
			_enginesList.push(engines[i].host);
			_engines.push(engines[i]);
			Settings.pref("middleClick", _enginesList);
			return;
		}
	}
};

function enginesRemove(id)
{
	for(let i = 0; i < _engines.length; i++)
	{
		if (_engines[i].name == id || _engines[i].host == id)
		{
			let n = _enginesList.indexOf(_engines[i].host);
			if (n != -1)
				_enginesList.splice(n, 1);

			Settings.pref("middleClick", _enginesList);
			_engines.splice(i, 1);
			return;
		}
	}
};

function enginesCheck(id)
{
	for(let i = 0; i < _engines.length; i++)
	{
		if (_engines[i].name == id || _engines[i].host == id)
			return i;
	}
	return -1;
};

function enginesFind(id, obj)
{
	obj = typeof(obj) == "undefined" ? window.engines : obj;
	for(let i = 0; i < obj.length; i++)
	{
		if (obj[i].name == id || obj[i].host == id)
			return i;
	}
	return -1;
};

function enginesSort(list, save)
{
	if (typeof(list) == "undefined")
	{
		list = ls("enginesSort") || [];
		save = true;
	}

	let newList = [],
			newEnginesList = [];

	for(let i = 0; i < list.length; i++)
	{
		let index = enginesFind(list[i]);
		if (index == -1 || newList.indexOf(window.engines[index].host) != -1)
			continue;

		newEnginesList[newEnginesList.length] = window.engines[index];
		newList[newList.length] = window.engines[index].host;
	}
	for(let i = 0; i < window.engines.length; i++)
	{
		if (newList.indexOf(window.engines[i].host) == -1)
		{
			newEnginesList[newEnginesList.length] = window.engines[i];
			newList[newList.length] = window.engines[i].host;
		}
	}
	for(let i in customLinks._list)
	{
		if (newList.indexOf(i) == -1)
		{
			newEnginesList[newEnginesList.length] = customLinks._list[i];
			newList[newList.length] = i;
		}
	}
	if (save)
		enginesSort._list = newList;

	window.engines = newEnginesList;
}
enginesSort.changed = function()
{
	let list = [];
	for (let i = 0; i < enginesDefault.length; i++)
	{
		list[list.length] = enginesDefault[i].host;
	}
	for (i in customLinks._list)
	{
		if (list.indexOf(i) == -1)
			list[list.length] = i;
	}
	return !isEqual(list, enginesSort._list);
}

function isEqual (a, b)
{
	for(let i in a)
	{
		if (!(i in b) || a[i] != b[i])
			return false
	}
	for(let i in b)
	{
		if (!(i in a) || a[i] != b[i])
			return false
	}
	return true;
}

function cleanName(id)
{
	return id.replace(/[^a-zA-Z0-9-_]/g, "_");
}

function getHost(url)
{
	let a = document.createElement('a');
	a.href = url;
	return a.hostname;
}
function engineFixHost(engine)
{
	if (engine.host)
		return;

	engine.host = getHost(engine.href);
}

function showHide(id, t)
{
	let hidden = _hidden.indexOf(id);
	if (typeof(t) == "undefined")
		return hidden != -1;

	if (t == 2)
		t = hidden == -1 ? 1 : 0;

	switch(t)
	{
		case 0:
			_hidden.splice(hidden, 1);
			if (!DB.savedColors[id])
				DB.infoRemove(id);

			hidden = false;
			break;
		case 1:
			if (hidden == -1)
			{
				_hidden.push(id);
				DB.infoAdd(id);
			}

			hidden = true;
			break;
	}
	let css = $("#css" + id);
	if (hidden)
	{
 		if (!css.length)
 		{
			let style = "<style id='css" + id + "'>"+
									"div.calendar:not(.showHidden).activeOnly .entry[data-series-id='" + id + "'][opened]:not(.multi){ display: block !important; }"+
									"div.calendar:not(.showHidden) .entry[data-series-id='" + id + "']:not([opened]):not(.searchResult){ display: none !important; }"+
									".entry[data-series-id='" + id + "'] .title{ font-style: italic; }"+
									"div:not(#searchResults) > .entry[data-series-id='" + id + "']:not([opened]):not(.searchResult){ opacity: 0.3;}"+
									".entry[data-series-id='" + id + "'] .showhide0{ display: inline; }"+
									".entry[data-series-id='" + id + "'] .showhide1{ display: none; }"+
									"</style>";
			$(style).appendTo("body");
		}
	}
	else
		css.remove();

	ls("hidden", _hidden);
	return hidden;
}


function command(id, val)
{
	if (!command.list[id])
		return false;

	try
	{
		command.list[id].func({preventDefault:function(){},stopPropagation:function(){}}, val);
	}
	catch(e)
	{
		return false;
	}
	return true;
}
command.list = {};
command.add = function(id, objId, func)
{
	command.list[id] = {
		id: id,
		objId: objId,
		func: func
	};
};

//watched checkbox
function watched(entry)
{
	if (entry._input.checked)
		watched.add(entry.getAttribute("data-series-id"), watched.title(entry));
	else
		watched.remove(entry.getAttribute("data-series-id"), watched.title(entry));

	watched.update(entry, entry._input.checked);
}
watched._list = ls("watched") || {};
watched._saving = false;
watched.add = function(id, episode)
{
	if (!watched._list[id])
		watched._list[id] = [];

	if (watched._list[id].indexOf(episode) == -1)
		watched._list[id].push(episode);

	watched.save();
};

watched.remove = function(id, episode)
{
	if (!watched._list[id])
		return;

	let n = watched._list[id].indexOf(episode);
	if (n == -1)
		return;

	watched._list[id].splice(n, 1);
	if (!watched._list[id].length)
		delete watched._list[id];

	watched.save();
};

watched.save = function(f)
{
	if (watched._saving && !f)
		return;

	function func()
	{
		watched._saving = false;
		ls("watched", watched._list);
	}
	clearTimeout(watched._saving);
	if (f)
		func();
	else
		watched._saving = setTimeout(func, 500);
};

watched.has = function(entry)
{
	let id = entry.getAttribute("data-series-id");
	return watched._list[id] && watched._list[id].indexOf(watched.title(entry)) != -1;
};

watched.title = function(entry)
{
	let txt = entry._title && entry._title._titleOrig ? entry._title._titleOrig : $(entry).find("div.title").text();
	return txt.substring(txt.lastIndexOf(" ") + 1).replace(/\s+$/g, "");
};

watched.update = function(entry, enable)
{
	let text = "Watched";
	if (enable)
	{
		entry.setAttribute("watched", "");
	}
	else
	{
		text = "Not watched";
		entry.removeAttribute("watched");
	}
	entry.title = $(entry).find(".title > span")[0].lastChild.textContent + " (" + text + ")";
	$(entry).find(".title > input").prop("title", text);
	entry._input.checked = enable;

};

watched.attach = function(i,entry)
{
	if (entry._input)
		return;

	let input = document.createElement("input");
	input.type = "checkbox";
	input.checked = watched.has(entry);
	entry._input = input;

	input.addEventListener("change", function(e)
	{
		let title = watched.title(entry);
		$('div.entry[data-series-id="' + entry.getAttribute("data-series-id") + '"]').each(function(i, entry)
		{
			if (watched.title(entry) == title)
				watched.update(entry, input.checked);
		});
		watched(entry);
	}, false);
	let title = $(entry).find(".title")[0],
			text = title.innerHTML;

	title.innerHTML = "";
	title.appendChild(input);
	$(title).append("<span>" + text.trim() + "</span>");
	watched.update(entry, input.checked);
};


//custom links
function customLinks(obj)
{

}
customLinks._list = ls("customLinks") || {};
customLinks.show = function()
{
	$(customLinks.div).show();
}
customLinks.hide = function()
{
	$(customLinks.div).hide();
}

customLinks.manager = function customLinksManager(callback)
{
	if (customLinks.div)
		return callback ? callback() : true;

	let html = multiline(function(){/*
<div id="manage-links-popup">
	<div id="manage-links-popup-content">
		<div class="header">
			<div class="back">
				<svg viewBox="0 0 24 24">
					<path d="M20,11V13H8L13.5,18.5L12.08,19.92L4.16,12L12.08,4.08L13.5,5.5L8,11H20Z" />
				</svg>
			</div>
			<h4>Links Manager</h4>
			<div class="close">
				<svg viewBox="0 0 24 24">
					<path d="M19,3H16.3H7.7H5A2,2 0 0,0 3,5V7.7V16.4V19A2,2 0 0,0 5,21H7.7H16.4H19A2,2 0 0,0 21,19V16.3V7.7V5A2,2 0 0,0 19,3M15.6,17L12,13.4L8.4,17L7,15.6L10.6,12L7,8.4L8.4,7L12,10.6L15.6,7L17,8.4L13.4,12L17,15.6L15.6,17Z"></path>
				</svg>
				<svg viewBox="0 0 24 24">
					<path d="M19,3H5A2,2 0 0,0 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5A2,2 0 0,0 19,3M19,19H5V5H19V19M17,8.4L13.4,12L17,15.6L15.6,17L12,13.4L8.4,17L7,15.6L10.6,12L7,8.4L8.4,7L12,10.6L15.6,7L17,8.4Z"></path>
				</svg>
			</div>
		</div>
		<div class="content"></div>
	</div>
</div>
		*/});//html

	let popup = $(html).appendTo("body");
	customLinks.div = popup[0];
	popup.find(".back").click(function()
	{
		customLinks.hide();
		setTimeout(function()
		{
			$("#account-overview").click();
		});
	});
	$(popup).find("[id^=account]").each(function()
	{
		this.id = this.id.replace("account", "manage-links");
	});

	let	content = $(popup).find(".content").html("");
	html = multiline(function(){/*
<div class="reset">
	<a id="sort-reset" href="#">reset sort</a>
</div>
<form>
	<div id="engine-edit">
		<div>
			<label>Name:</label>
			<input id="engine-name">
		</div>
		<div>
			<label>URL:</label>
			<input id="engine-url">
			<select id="engine-tags" size="1">
				<option value=""></option>
				<option value="MONKEY_N">Name</option>
				<option value="MONKEY">Name+Episode</option>
				<option value="MONKEY_ID">ID</option>
				<option value="{WIKI_TITLE}">Wiki page</option>
				<option value="MONKEY_ARCHIVELINK">Archive link</option>
			</select>
		</div>
		<div>
			<label>ID:</label>
			<input id="engine-id" placeholder="&lt;optional&gt;">
		</div>
		<div>
			<label></label>
			<input id="engine-submit" type="button" value="Add">
			<input id="engine-reset" type="reset" value="Reset">
		</div>
		<div>
			<label>Result:</label>
			<div id="engine-res"></div>
		</div>
	</div>
</form>
	*/});//html

	$(html).appendTo(content.parent());
	let engId = $("#engine-id"),
			engUrl = $("#engine-url"),
			engName = $("#engine-name"),
			engSubmit = $("#engine-submit"),
			engTags = $("#engine-tags"),
			engRes = $("#engine-res"),
			engReset = $("#engine-reset"),
			engSortReset = $("#sort-reset"),
			engResHidden = $('<div id="engine-hidden" class="entry" data-series-id="1234" data-series-source="List of Monsuno episodes" data-date="20120223"><div class="title">Monsuno S01E01</div></div>').appendTo(popup),
			prevTarget = null,
			prevVal = null;

			if (enginesSort.changed())
				popup.attr("changed", true);

	function change(e)
	{
		if (prevTarget === e.target && prevVal === e.target.value)
			return;

		clearTimeout(change.timer);
		change.timer = setTimeout(function()
		{
			prevVal = e.target.value;
			prevTarget = e.target;
			engResHidden.find(".details").remove();
			let opened = $('.details[style="display: block;"]').toggleClass("details", false);
			enginesBackup();
			let eng = [{
						name: engName.val(),
						host: engId.val(),
						href: engUrl.val()
					}];

			if (!eng[0].href.match(/[a-z]+:\/\//i))
				eng[0].href = "http://" + eng[0].href;

			engineFixHost(eng[0]);
			window.engines = eng;
			engResHidden.find(".title").trigger("click");
			opened.toggleClass("details", true);
			setTimeout(function()
			{
				let list = engResHidden.find(".engines").children(),
						a = list.filter("a")[0],
						img = list.filter("img")[0],
						children = engRes.children();

				img.src = "http://www.google.com/s2/favicons?domain=" + getHost(eng[0].href);

				if (!children.length)
				{
					engRes.append(img).append(a);
				}
				else
				{
					$(children[0]).replaceWith(img);
					$(children[1]).replaceWith(a);
				}
				if (enginesBackup)
				{
					enginesRestore();
				}
			});
		}, 300);
	}//change()
	engId.on("input change", change);
	engUrl.on("input change", change);
	engName.on("input change", change);

	engTags.on("change", function(e)
	{
		let start = engUrl[0].selectionStart,
				end = engUrl[0].selectionEnd,
				endNew = start + e.target.value.length,
				startNew = endNew,
				txt = engUrl.val();
		engUrl.val(txt.substring(0, start) + e.target.value + txt.substring(end));
		engUrl[0].selectionStart = startNew;
		engUrl[0].selectionEnd = endNew;
		engUrl.focus();
		engUrl.trigger("input");
		e.target.value = "";
	});
	engReset.click(function(e)
	{
		engRes.html("");
		prevVal = null;
	});
	function flash(obj, color)
	{
		obj.toggleClass("update", false);
		obj.css("background-color", color ? color : "#90FF90");
		setTimeout(function()
		{
			obj.toggleClass("update", true);
			obj.removeAttr("style");
		}, 100);
	}
	engSubmit.click(function(e)
	{
		let engine = {
					name: engName.val().trim(),
					href: engUrl.val().trim(),
					host: engId.val().trim()
				};
		if (!engine.href.match(/[a-z]+:\/\//i))
			engine.href = "http://" + engine.href;

//		engUrl.val(engine.href);
		engineFixHost(engine);
		let id = "engine_" + cleanName(engine.host),
				update = $("#" + id),
				exists = customLinks._list[engine.host];

		if (!engine.name || !engine.href)
			return false;

		let equal = false,
				n = -1;
		for(let i = 0; i < window.engines.length; i++)
		{
			if (window.engines[i].host == engine.host)
			{
				equal = isEqual(window.engines[i], engine);
				n = i;
				break;
			}
		}
		if (equal)
		{
			flash(update);
			return false;
		}

		if (!exists || update.length)
		{
			customLinks._list[engine.host] = engine;
			if (update.length)
			{
				if (n > -1)
					window.engines[n] = engine;

			}
			else
				window.engines.push(engine);

			ls("customLinks", customLinks._list);
			customLinksAddCss(id);
		}
		function updater(update)
		{
			flash($(update));
			updateDetails();
		}
		if (update.length)
		{
			if (exists)
			{
				for (let i = 0; i < enginesDefault.length; i++)
				{
					if (isEqual(enginesDefault[i], engine))
					{
						update.find(".del").trigger("click");
						return;
					}
				}
			}
			update.replaceWith(create(engine, !exists ? updater : function(update)
			{
				flash($(update));
			}));
			let entry = $("div.entry").find("." + id);
			entry.filter("a.link").attr("href", engine.href).text(engine.name);
			flash(update);
		}
		else
		{
			let last = content.children(":last-child");
			content.append(create(engine, updater));
//			updateDetails();
		}

		engName.val("");
		engId.val("");
		engUrl.val("");
	});//engSubmit.click()

	function updateDetails()
	{
		let clone = engResHidden.clone();
		clone.find(".details").remove();
		$("body").append(clone);
		let opened = $('.details[style="display: block;"]').toggleClass("details", false);
		force = true;
		clone.find(".title").trigger("click");
		opened.toggleClass("details", true);
		setTimeout(function()
		{
			$('div:not(#engine-hidden) .details[style="display: block;"]').find(".engines").replaceWith(clone.find(".engines"));
			clone.remove();
		}, 300);
	}
	engSortReset.click(function(e)
	{
		e.stopPropagation();
		e.preventDefault();
		let host = engId.val(),
				name = engName.val(),
				href = engUrl.val(),
				list = [];

		for (let i = 0; i < enginesDefault.length; i++)
		{
			list[list.length] = enginesDefault[i].host;
		}
		for (i in customLinks._list)
		{
			list[list.length] = customLinks._list[i].host;
		}
		enginesSort(list, true);
		ls("enginesSort", []);
		updateDetails();
		$(customLinks.div).remove();
		customLinks.div = null;
		popup.removeAttr("changed");
		customLinks.manager(function()
		{
			if (host || name || href)
			{
				$("#engine-id").val(host);
				$("#engine-name").val(name);
				$("#engine-url").val(href);
				$("#engine-url").trigger("input");
			}
		});
		customLinks.show();
	});
	let dragged = null;

	function dndEvent(e)
	{
		let r = null;
		switch(e.type)
		{
			case "mousedown":
				if (typeof(e.target.className) != "string" || e.target.className.indexOf("dndh") != -1)
					dragged = e.target.parentNode;
				break;
			case "dragstart":
				if (!dragged)
					return;

				e.dataTransfer.effectAllowed = 'move';
				dragged = this;
				dragged.classList.add("dragging");
				this.parentNode.classList.add("dragging");
				setTimeout(function()
				{
					dragged.classList.add("hide");
				});
				e.dataTransfer.setData('application/x-moz-node', dragged);
				break;
			case "dragenter":
				if (!dragged)
					return;

				let node = this,
						up = (node.nextSibling == dragged),
						moveold = up ? node : node.nextSibling,
/*
						anim1 = up ? "up" : "down",
						anim2 = up ? "down" : "up",
*/
						movenew = dragged;
/*
				movenew.classList.add(anim1);
				moveold.classList.add(anim2);
				movenew.classList.remove(anim2);
				moveold.classList.remove(anim1);
//				$(dragged).toggleClass(anim1, true);
//				$(moveto).toggleClass(anim2, true);
//				clearTimeout(dragged.__timer);
//				clearTimeout(moveto.__timer);
				movenew.__timer = setTimeout(function()
				{
					movenew.classList.remove(anim1);
//					$(dragged).toggleClass(anim1, false);
				}, 1000);
				moveold.__timer = setTimeout(function()
				{
					moveold.classList.remove(anim2);
//					$(moveto).toggleClass(anim2, false);
				}, 1000);
*/
				node.parentNode.insertBefore(movenew, moveold);
				break;
			case "dragover":
				if (!dragged)
					return;

				e.dataTransfer.dropEffect = 'move';
				if (e.stopPropagation)
					e.stopPropagation();

				if (e.preventDefault)
						e.preventDefault(); // Necessary. Allows us to drop.

				r = false;
				break;
			case "dragleave":
				break;
			case "dragend":
				if (!dragged)
					return;

				dragged.classList.remove("dragging");
				dragged.classList.remove("hide");
				let div = document.querySelectorAll('#manage-links-popup-content .content [draggable]'),
						list = [];
				[].forEach.call(div, function (col)
				{
					list[list.length] = col._engine.host;
				});
				dragged.parentNode.classList.remove("dragging");
				enginesSort(list, true);
				ls("enginesSort", list);
				if (enginesSort.changed())
					popup.attr("changed", true);
				else
					popup.removeAttr("changed");

				updateDetails();
				dragged = false;
				break;
			case "drop":
				if (!dragged)
					return;

				if (e.stopPropagation)
					e.stopPropagation();
				if (e.preventDefault)
						e.preventDefault(); // Necessary. Allows us to drop.
				break;
		}
		if (r !== null)
			return r;
	}
	function create(engine, callback)
	{
		let div = document.createElement("div"),
				id = "engine_" + cleanName(engine.host),
				cb = createCheckbox(id, "", enginesHide.indexOf(engine.host) == -1, function(e, id, checked)
				{
					if (checked)
						enginesHide.splice(enginesHide.indexOf(engine.host), 1);
					else
						enginesHide.push(engine.host);

					ls("enginesHide", enginesHide);
			}, ["Visible", "Hidden"]),
				dndHandle = document.createElement("span");
		div._engine = engine;
		div.id = id;

		content[0].setAttribute("draggable", true);
		div.setAttribute("draggable", true);
		div.addEventListener('dragstart', dndEvent, false);
		div.addEventListener('dragenter', dndEvent, false)
		div.addEventListener('dragover', dndEvent, false);
		div.addEventListener('dragleave', dndEvent, false);
		div.addEventListener('drop', dndEvent, false);
		div.addEventListener('dragend', dndEvent, false);
		div.addEventListener("mousedown", dndEvent, false);

		dndHandle.innerText = "☰";
		dndHandle.className = "dndh";
		div.appendChild(dndHandle);
		div.appendChild(cb);
		let clone = engResHidden.clone();
		$("body").append(clone);
		clone.find(".details").remove();
		let opened = $('.details[style="display: block;"]').toggleClass("details", false);

		enginesBackup();
		window.engines = [engine];
		clone.find(".title").trigger("click");
		opened.toggleClass("details", true);
		let n = 100;
		setTimeout(function loop()
		{
//			let list = clone.find(".engines").children().filter(".engine_" + cleanName(engine.host)),
			let list = clone.find(".engines").children();
			if (!list.length && n--)
			{
				setTimeout(loop);
				return;
			}
			let	a = list.filter("a")[0],
					img = list.filter("img")[0],
					def = false;

			for (let i = 0; i < enginesDefault.length; i++)
			{
				if (enginesDefault[i].host == engine.host)
				{
					def = true;
					break;
				}
			}
			if (a && img)
				img.src = "http://www.google.com/s2/favicons?domain=" + getHost(a.href);

			$(div).append(img);
			$(div).append(a);
			if (def)
				$(div).toggleClass("def", true);

			enginesRestore();
			clone.remove();

			$('<span class="edit" title="Edit"><svg viewBox="0 0 24 24"><path d="M20.71,7.04C21.1,6.65 21.1,6 20.71,5.63L18.37,3.29C18,2.9 17.35,2.9 16.96,3.29L15.12,5.12L18.87,8.87M3,17.25V21H6.75L17.81,9.93L14.06,6.18L3,17.25Z"></path></svg></span>').appendTo(div).click(function(e)
			{
				engId.val((getHost(engine.href) == engine.host) ? "" : engine.host);
				engName.val(engine.name);
				engUrl.val(engine.href.replace(/http:\/\//i, ""));
				engId.trigger("input");
			});
			if (customLinks._list[engine.host])
			{
	//				$('<span class="del" title="delete">&#9249;</span>').appendTo(div).click(function(e)
				$('<span class="del" title="' + (def ? "Clear" : "Delete") + '">' + '<svg viewBox="0 0 24 24"><path d="M19,4H15.5L14.5,3H9.5L8.5,4H5V6H19M6,19A2,2 0 0,0 8,21H16A2,2 0 0,0 18,19V7H6V19Z"></path></svg>' + '</span>').appendTo(div).click(function(e)
				{
					e.stopPropagation();
					e.preventDefault();
					flash($("#" + id), e.isTrigger ? null : "#FF9090");
					setTimeout(function()
					{
						let host = engId.val(),
								name = engName.val(),
								href = engUrl.val();

						delete customLinks._list[engine.host];
						let update = false;
						for(let i = 0; i < window.engines.length; i++)
						{
							if (window.engines[i].host == engine.host)
							{
								for(let d = 0; d < enginesDefault.length; d++)
								{
									if (enginesDefault[d].host == engine.host)
									{
										update = d;
										break;
									}
								}
								if (update !== false)
									window.engines[i] = enginesDefault[update];
								else
								{
									let index = enginesSort._list.indexOf(engine.host);

									if (index != -1)
									{
										enginesSort._list.splice(i, 1);
										ls("enginesSort", enginesSort._list);
									}
									window.engines.splice(i, 1);
								}
								break;
							}
						}
						ls("customLinks", customLinks._list);
						if (update === false)
						{
							$("#" + id).remove();
							$(".engines").find("." + id).remove();
							$("." + id).toggleClass(id, false);
							$("#css_" + id).remove();
							let index = enginesHide.indexOf(engine.host);
							if (index != -1)
							{
								enginesHide.splice(index, 1);
								ls("enginesHide", enginesHide);
							}
						}
						$(customLinks.div).remove();
						customLinks.div = null;
						customLinks.manager(function()
						{
							if (update !== false)
							{
								let aNew = $("#manage-links-popup").find("#" + id).find("a.link"),
										a = $('.details[style="display: block;"]').find(".engines").find("a." + id);

								a.html(aNew.html());
								a.attr("href", aNew.attr("href"));
							}
							if (host || name || href)
							{
								$("#engine-id").val(host);
								$("#engine-name").val(name);
								$("#engine-url").val(href);
								$("#engine-url").trigger("input");
							}
						});
						customLinks.show();
					}, 200);
				});
			}
			if (callback)
				callback(div);
		});
		return div;
	}//create();
	enginesBackup();

	let eng = window.engines,
			n = eng.length;
	function finished()
	{
		if (!--n)
			callback();
	}
	for(let i = 0; i < eng.length; i++)
	{
		content.append(create(eng[i], callback ? finished : null));
	};
	setTimeout(enginesRestore,100);
}//customLinks.manager()

function customLinksAdd()
{

	let listNew = [],
			remove = [],
			list = [];
	for(let l in customLinks._list)
	{
		listNew.push(customLinks._list[l]);
	}
	let hosts = [];
	for(let n = 0; n < window.engines.length; n++)
	{
		hosts[hosts.length] = window.engines[n].host;
		enginesDefault[enginesDefault.length] = window.engines[n];
	}
	for(let i = 0; i < listNew.length; i++)
	{
		let n = hosts.indexOf(listNew[i].host);
		if (n != -1)
			window.engines[n] = listNew[i];
		else
			list.push(listNew[i]);

		customLinks._list[listNew[i].host] = listNew[i];
	}
	ls("customLinks", customLinks._list);
	window.engines = window.engines.concat(list);

	enginesSort();
	let css = [],
			css2 = [];

	for (let i = 0; i < window.engines.length; i++)
	{
		let id = "engine_" + cleanName(window.engines[i].host);
		customLinksAddCss(id);
	}
	customLinks.manager();
	$(customLinks.div).remove();
	customLinks.div = null;


	//middle click on day's title opens selected engines for user's shows
	_enginesList = Settings.pref("middleClick") || [];
	let engines = enginesBackup.backup ? enginesBackup.backup : window.engines,
			del = [],
			add = [];

	for(let i = 0; i < _enginesList.length; i++)
	{
		let found = false;
		for (let n = 0; n < engines.length; n++)
		{
			if (engines[n].name == _enginesList[i])
				_enginesList[i] = engines[n].host

			if (engines[n].host == _enginesList[i])
			{
				_engines.push(engines[n]);

				if (!i && engines[n].host == "thepiratebay.org")
				{
					//sort by date instead of seeds
					engines[n].href = engines[n].href.replace(/\.se\//, ".org").replace(/\/0\/7\/0$/, "/0/3/0");
				}

				found = true;
				break
			}
		}
		if (!found)
			del.push(_enginesList[i]);
	}
	for(let i = 0; i < del.length; i++)
	{
		_enginesList.splice(_enginesList.indexOf(del[i]), 1);
	}
	let l = _enginesList.length;
	try
	{
		_enginesList = Array.from(new Set(_enginesList));
	}catch(e){}
	if (l != _enginesList)
		Settings.pref("middleClick", _enginesList);

}//customLinksAdd()

function customLinksAddCss(id)
{
	let css = 'body:not(.' + id + ') .engines .' + id + "{display:none;}",
			css2 = 'body:not(.' + id + ') #' + id + " img";

	css2 += ',body:not(.' + id + ') #' + id + " a.link";
	css2 += "{font-style: italic; opacity: 0.5;}";
	$('<style id="css_' + id + '"></style>').html(css+css2).appendTo("head");
}


function createCheckbox(id, label, cookie, callback, title, className)
{
	let span = document.createElement("span"),
			checkon = document.createElement("span"),
			checkoff = document.createElement("span"),
			a = document.createElement("a"),
			check = typeof(cookie) == "boolean" ? cookie : cs(cookie) ? true : false;
	if (title)
	{
		checkon.title = title[0];
		checkoff.title = title[1] || title[0];
		a.title = title[2] || title[0];
	}
	a.className = (typeof(className) == "undefined" ? "filter " : className + " ") + id;
	checkon.className = "checkon nu";
	checkoff.className = "checkoff nu";
	checkon.innerHTML = "☑";
//	checkon.innerHTML = '<svg style="width:1em;height:1em;" viewBox="0 0 24 24"><path d="M19,19H5V5H15V3H5C3.89,3 3,3.89 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V11H19M7.91,10.08L6.5,11.5L11,16L21,6L19.59,4.58L11,13.17L7.91,10.08Z" /></svg>';
	checkoff.innerHTML = "☐";
//	checkoff.innerHTML = '<svg style="width:1em;height:1em;" viewBox="0 0 24 24"><path d="M19,3H5C3.89,3 3,3.89 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5C21,3.89 20.1,3 19,3M19,5V19H5V5H19Z" /></svg>';
//	a.href = "#";
	span.appendChild(checkon);
	span.appendChild(checkoff);
	span.appendChild(document.createTextNode(label));
	a.appendChild(span);
	$(a).insertBefore("#nu-showing");
	let func = function(e, val)
	{
		e.preventDefault();
		e.stopPropagation();
		let check = span.hasAttribute("checked");
		if (val !== undefined)
			check = !val;

		if (check)
			span.removeAttribute("checked");
		else
			span.setAttribute("checked", "checked");

		$(".calendar").toggleClass(id, !check);
		$("body").toggleClass(id, !check);
		if (typeof(cookie) != "boolean")
			cs(cookie, check ? 0 : 1);

		return (typeof(callback) == "function") ? callback(e, id, !check) : e;
	};
	command.add(cookie, id, func);
	a.addEventListener("click", func, false);
	if (check)
		span.setAttribute("checked", "checked");

/*
//real checkboxes
	let box = document.createElement("span"),
			labelNode = document.createElement("label"),
			checkbox = document.createElement("input"),
			checkboxId = "cb_" + id,
			suf = "",
			i = 1;
	checkbox.type = "checkbox";
	box.className = (typeof(className) == "undefined" ? "filter " : className + " ") + id;
	if (title)
		box.title = title[0];

	labelNode.textContent = label;
	box.appendChild(checkbox);
	box.appendChild(labelNode);
	
	while($("#" + checkboxId + suf).length)
	{
		suf = "_" + i++;
	}
	checkbox.addEventListener("change", func, false);
	checkbox.id = checkboxId + suf;
	checkbox.checked = check;
	labelNode.setAttribute("for", checkbox.id);
	$(box).insertBefore("#nu-showing");
*/
	$(".calendar").toggleClass(id, check);
	$("body").toggleClass(id, check);

	return a;
}

function rand(min, max)
{
	return Math.floor(Math.random() * (max - min + 1)) + min;
}

(function loop()
{
	if ((typeof(engines) == "undefined" || !engines.length) && --loo)
		return setTimeout(loop, 0);

	if (!loo)
		return;

	Settings.init();
	customLinksAdd();
})();


let func = function(event)
{
	Settings.init();

	// fix highlighting today would remove /u/user ..
	$( "#linkToday" ).click(function click(e)
	{
		e.stopPropagation();
		e.preventDefault();
		e.stopImmediatePropagation();
		loadArchiveFromPathname("#today", "#today");
		return false;  
	});

	let _today,
			showHidden = Settings.pref("showHidden") ? true : false;
			_assignColor = assignColor;

	/*
	work around for expand/collapse same series in one day
	*/
	window.assignColor = function assignColor ( seriesId, color, permanent )
	{
		let r = _assignColor(seriesId, color, permanent),
				css = $("#css_"+seriesId),
				html = css.html();

		if (html)
			css.html(html.replace(/(\s+)(\.activeOnly)([^\{]+)\{/, "$1$2$3:not(.multi),body:not(.collapseMulti) $2$3,$2 .day.expand $3,$2 .day.opened $3{"));

		return r;
	};
	/*
	fixing browser history inflating after each page refresh and prev/next history jump don't work
	*/
	var prevPath;
	//MS Edge get's /undefined in the address
	if (window.location.pathname.match(/\/undefined/))
	{
		history.go(-1);
		let path = window.location.href;
		history.go(1)
		history.replaceState({}, "", path);
		history.go(-1);
	}

	function loadArchiveFromPathname(originalPath,highlightSelector)
	{
		path = originalPath||document.location.pathname;
		var match = path.match(/^\/archive\/([0-9]+)-([0-9]+)$/);
		var ym = match && match.length == 3? (~~match[1]*12+~~match[2]-1) : ymToday;
	//start fix - browser history inflating after each page refresh
		if (originalPath && prevPath != originalPath)
		{
			prevPath = originalPath;
			history.pushState({originalPath:originalPath,highlightSelector:highlightSelector}, "", originalPath);
		}

	//end fix
		$("#archive-prev").attr("href", "/archive/" + ym2str(ym-1));
		$("#archive-next").attr("href", "/archive/" + ym2str(ym+1));
		$("body").toggleClass("archive", !!match&&match.length==3);
		$("#leaveArchive").text(ym>ymToday?"Leave future":"Leave archive");

		let whenDone = function(){
			// set title
			$("#archive-current").text((!!match&&match.length==3)?ym2str(ym):"Go waste your time");
			// highlight today with a happy yellow background
			$( "div.day[data-date='" + today.getFullYear() + pad2( today.getMonth() + 1 ) + pad2( today.getDate() ) + "']" ).addClass( "today" ).attr( "id", "today" );
			markSearchResults();

			var $hl = $(highlightSelector||".does-not-exist-and-never-will");
			if($hl.get().length>0){
				// blink
				for( var i = 0; i < 8; i++ ) $hl.animate( {"opacity":i%2}, 1 ).delay( 100 );

				// scroll to
				var val = function(){return $hl.offset().top-Math.max(document.documentElement.clientHeight, window.innerHeight || 0)/2;};
				$('html, body').animate({
							scrollTop: val()
					},{duration:500, step:function(top,info){
						info.end = val();
					}});
			}
	//injecting userscript function execution
			showPast(function()
			{
	//adding watched checkboxes
				$("div.day > div.entry").each(watched.attach);
	//collapse multiple entries of the same series in one day
				$("div.day").each(collapseMulti);
			});
			showHideLoad();
		};

		if(ymCurrent != ym)
		{
			$(".days").load("/_archive/" + ~~(ym/12) + "-" + ~~((ym%12)+1), function()
			{
				ymCurrent = ym;
				whenDone();
			});
		}
		else
		{
			whenDone();
		}
	}
	window.loadArchiveFromPathname = loadArchiveFromPathname;
	/*
	end fixing browser history inflating after each page refresh and prev/next history jump don't work
	*/

	//collapse multiple entries of the same series in one day
	let collapseMulti = function collapseMulti(i, day)
	{
		if (!$(day).find("div.entry > .title > span").length)
			return;

		if (day.list)
		{
			collapseMulti.setTitle(day.list, Settings.prefs.collapseMulti && !$(day).hasClass("opened") ? "_titleCollapsed" : "_titleOrig");
			return;
		}
		day.list = {};
		let list = {};
		day.addEventListener("mouseenter", function(e)
		{
			collapseMulti.mouseOver(e, day);
		}, true);
		day.addEventListener("mouseleave", function(e)
		{
			collapseMulti.mouseOut(e, day);
		}, true);

		$(day).find("div.entry").each(function(i, entry)
		{
			let id = entry.getAttribute("data-series-id");
			entry._title = $(entry).find(".title>span");
			entry._title._titleOrig = entry._title.text();
			if (list[id])
				$(entry).toggleClass("multi", true);
			else
			{
				list[id] = [];
			}

			list[id].push(entry);
		});
		for(let i in list)
		{
			if (list[i].length < 2)
				continue;

			list[i][0]._title._titleCollapsed = list[i][0]._title.text() + "-" + list[i][list[i].length - 1]._title.text().replace(/.* ([^ ]+)$/, "$1");
			$(list[i][0]).toggleClass("multif", true);

			day.list[i] = list[i][0]._title;
			if (Settings.prefs.collapseMulti)
				$(day.list[i]).html(day.list[i]._titleCollapsed);
		}
	};


	collapseMulti.setTitle = function(list, title)
	{
		for (let i in list)
			$(list[i]).html(list[i][title]);
	};

	collapseMulti.mouseOver = function(e, day)
	{
		if (e.target != day)
			return;

		day._type = "over";
		clearTimeout(day._collapseMultiTimer);
		if (Settings.prefs.animateExpand)
		{
			let func = function()
			{
				collapseMulti.animate(day, "expand", true, Settings.prefs.collapseMulti ? "_titleOrig" : "");
			};
			if (!$(day).hasClass("expand") && !$(day).hasClass("opened"))
			{
				func();
			}
			else
			{
				$(day).toggleClass("expand", true);
				if (!Settings.prefs.collapseMulti)
					return;

				collapseMulti.setTitle(day.list, "_titleOrig");
			}
		}
		else
		{
			$(day).toggleClass("expand", true);
			if (!Settings.prefs.collapseMulti)
				return;

			collapseMulti.setTitle(day.list, "_titleOrig");
		}
	};

	collapseMulti.mouseOut = function(e, day, id)
	{
		if (e.target != day)
			return;

		day._type = "out";
		day._collapseMultiTimer = setTimeout(function()
		{
			if (Settings.prefs.animateExpand)
			{
				collapseMulti.animate(day, "expand", false, Settings.prefs.collapseMulti && !$(day).hasClass("opened") ? "_titleCollapsed" : "")
			}
			else
			{
				$(day).toggleClass("expand", false);
				if (!Settings.prefs.collapseMulti)
					return;

				if (!$(day).hasClass("opened"))
					collapseMulti.setTitle(day.list, "_titleCollapsed");
			}
		}, 300)
	};

	collapseMulti.animateDone = function(e, n)
	{
		e.elem.style.overflow = "";
		e.elem.style.height = "";
		e.elem.style.display = "";
		e.elem.style.textOverflow = "";
		$(e.elem).find(".title").css("white-space", "");
	};
	collapseMulti.animate = function(day, cl, val, title)
	{
		if (!day._animatingQuie)
			day._animatingQuie = {};

		if (day._animating)
		{
			clearTimeout(day._animatingQuie[cl+val]);
			return day._animatingQuie[cl+val] = setTimeout(function()
			{
				collapseMulti.animate(day, cl, val, title);
			});
		}

		let type = day._type;
		if (Settings.prefs.collapseMulti)
			clearTimeout(day._collapseMultiTimer);

		let clone = day.cloneNode(true);
		$(clone).toggleClass(cl, val);
		if (title)
		{
			clone.list = {};
			for (let i in day.list)
			{
				clone.list[i] = $($(clone).find(".multif[data-series-id=" + i + "]")[0]);
				clone.list[i]._titleCollapsed = day.list[i]._titleCollapsed;
				clone.list[i]._titleOrig = day.list[i]._titleOrig;
			}
			collapseMulti.setTitle(clone.list, title);
		}
		clone.style.visibility = "hidden";
		clone.style.position = "absolute";
		clone.style.top = 0;
		clone.style.width = day.clientWidth + "px";
		$(clone).toggleClass("clone", true);
		day.parentNode.appendChild(clone);
		let n = 0;
		collapseMulti.setTitle(day.list, title);
		let stopped = false;
		day._animating = true;
		$(clone).find(".entry").each(function(i, c)
		{
			n++;
			let e = $(day).find(".entry")[i];
			e.style.height = (e.clientHeight ? e.clientHeight : 1) + "px";
			e.style.overflow = "hidden";
			e.style.textOverflow = "unset";
			e.style.display = "block !important";
			$(e).find(".title").css("white-space", "normal");
			$(e).show();
			$(e).css("display", "block !important");
			if (!$(e).is( ":visible" ))
			{
				e.style.setProperty("display", $(c).css("display"), "important");
			}
			$(e).stop(true);
			$(e).animate({
				height: c.clientHeight,
			},
			{
				duration: 200,
				progress: function(e)
				{
					if (day._type != type)
					{
						e.stop(true);
						stopped = true;
					}
				},
				always: function(e)
				{
					if (!--n)
					{
						if (!stopped)
							$(day).toggleClass(cl, val);

						day._animating = false;
					}
					collapseMulti.animateDone(e);
				}
			});
		});
	};

	collapseMulti.onOff = function(e, id, checked)
	{
		Settings.prefs.collapseMulti = checked;
		$("div.day").each(collapseMulti);
		Settings.callback(e, id, checked);
	};

	//fixing prev/next history jump does nothing
	$(window).on("popstate", function(e)
	{
		let state = e.originalEvent.state;
		prevPath = (state ? state.originalPath : undefined) || e.target.location.pathname;

		loadArchiveFromPathname(prevPath, state ? state.highlightSelector : undefined);
	});

	function showPast(callback)
	{

	// hide all past days
		let	d = new Date();

		_today = $("div.day[data-date='" + d.getFullYear() + pad2((new Date()).getMonth() + 1) + pad2((new Date()).getDate()) + "']");

		if (!_today || $(".archive").length)
		{
			if (callback)
				return callback();

			return;
		}

		let	firstDay = $(".days").children().first(),
				firstDate = firstDay.attr("data-date");

		if (!firstDay.length)
			return;

		let div = [document.createElement("div")],
				y = firstDate.slice(0, 4),
				m = firstDate.slice(4, 6);

		if (parseInt(firstDate.slice(6, 8)) < 15)
			div.push(document.createElement("div"));

		let c = div.length;
		for (let n = 0; n < div.length; n++)
		{
			let d = new Date(y, m - n - 1);
			$(div[n]).load("/_archive/" + d.getFullYear() + "-" + pad2(d.getMonth() + 1), pastLoadDone);
		}
		function pastLoadDone()
		{
			if (--c > 0)
				return;

			let found = false,
					func = function (i, o)
					{
						if ($(this).attr("data-date") == firstDate)
							found = true;

						if (found)
							$(this).remove();
					};
			for (let n = 0; n < div.length; n++)
			{
				found = false;
			//remove any duplicate dates that already exist;
				$(div[n]).children().each(func);
				$(div[n]).children().prependTo($("div.days"));
			}
			pastLoaded();
			if (callback)
				callback();
		}
	}//showPast()

	function pastLoaded()
	{
		let	hasLoaded = $("#pastWeeks").length,
				stop = false;

		$("div.days").children().each(function(i, o)
		{
			if ($(this).is(_today))
			{
				$(this).attr("today", "true");
				stop = true;
			}
			if (stop)
			{
				$(this).removeClass("past");
			}
			else
			{
				$(this).addClass("past");
			}
		});

		let week = ["mon", "tue", "wed", "thu", "fri", "sat", "sun"],
				match = $(_today).find(".date").text().toLowerCase().match(/([^,]{3})/),
				daysNum = match ? week.indexOf(match[1]) : -1;

		let prev = _today.prev();
		//there is no identication of which week a day belong to, so we must make sure that previous days of current week don't count as previous week.
		if (daysNum > 0)
		{
			for(let i = 0; i < daysNum && prev; i++)
			{
				prev.removeClass("past");
				prev = prev.prev();
			}
		}
		//remove more then 4 weeks worth of days.
		for(let i = 0; i < 27 && prev; i++)
		{
			prev = prev.prev();
		}
		if (prev)
		{
			let found = false,
					func = function(i, o)
					{
						if (found)
							return;

						if ($(this).is(prev))
							found = true;
						else
							$(this).remove();
					};
			$("div.days").children().each(func);
		}
		let	daysPast = $('div.past'),
				weeks = parseInt(Settings.pref("weeks")),
				weeksMax = Math.round((daysPast.length) / 7);//how many past weeks do we have available?

		if (isNaN(weeks))
			weeks = readCookieRaw("p") == "1" ? weeksMax : 0;

		if (weeks > weeksMax)
			weeks = weeksMax;

		//main function that shows/hides past days
		function showWeeks()
		{

			//get week numbers from dropdown
			let weeks = parseInt($("#pastWeeks").val());

			//just some sanity check
			if (weeks * 7 > daysPast.length)
				weeks = weeksMax;

			if (weeks < 1)
				weeks = 0;

			for(let i = weeksMax; i > 0; i--)
				$( "div.calendar" ).toggleClass("showPast" + i, (weeks >= i));

			Settings.pref("weeks", weeks);
		}
		//add new class pastNN to each past day, where NN is a week number.
		let func = function(i)
		{
			$(this).addClass("past" + (Math.ceil((daysPast.length - i) / 7 % (weeksMax + 1))));
		};
		daysPast.each(func);

		if (!hasLoaded)
		{
			//create dropdown menu with number of available past weeks
			let dropdown = document.createElement("select");
			dropdown.id = "pastWeeks";

			for(let i = 0; i <= weeksMax; i++)
			{
				let option = document.createElement("option");
				option.value = i;
				option.text = i;
				option.selected = (weeks == i);
				dropdown.appendChild(option);
			}

			//add event listener to dropdown
			$(dropdown).change(showWeeks);

			let span = document.createElement("span");
			span.id = "past-weeks";
			span.appendChild(document.createTextNode("Show past weeks:"));
			span.appendChild(dropdown);
			//insert our dropdown and new text into document
			$(".calendar").prepend(span);

			//hide "Show/Hide past month" links
			$("#past-showing").toggle(true);
			//togglePast();//make sure we disable "Show past month"
			$("#past-showing").toggle(false);
			$("#past-hidden").toggle(false);
		}
		showWeeks();
	}//pastLoaded()

	var prevOpened = null,
			prevParentOpened = null,
			prevParentOpenTimer = null;
	//adding attribute "opened" to the entry allows us show/hide things from CSS based on entry state
	$("body").on("click", "div.entry div.title", function(e)
	{
		if (e.isTrigger)
			return;

		let $entry = $( this ).parent(),
				parent = $entry.parent();

		if (prevOpened)
		{
			let po = prevOpened,
					ppo = prevParentOpened;

			prevParentOpenTimer = setTimeout(function()
			{
				collapseMulti.setTitle(ppo[0].list, Settings.prefs.collapseMulti && !ppo.hasClass("expand")? "_titleCollapsed" : "_titleOrig");

				po.parent().toggleClass("opened", false);
			}, 400);

			prevOpened.attr("opened", "");
			setTimeout(function()
			{
				po.removeAttr("opened");
			}, 300);
			prevOpened = null;
		}


		if ($entry.attr("opened") === undefined)
		{
			$entry.attr("opened", "");
			parent.toggleClass("opened", true);
			collapseMulti.setTitle(parent[0].list, "_titleOrig");
	//idealy this should've been done via "on complete" function submitted for slideUp/slideDown
			if (prevParentOpened && parent[0] == prevParentOpened[0])
				clearTimeout(prevParentOpenTimer);

			setTimeout(function()
			{
				$entry.attr("opened", "1");
			}, 300);

			prevParentOpened = parent;
			prevOpened = $entry;
		}
	});

	//create stylesheet. A little trick to have multi-line text in javascript
	let	style = document.createElement("style"),
			css = multiline(function(){/*
	svg
	{
		width: 1em;
		height: 1em;
	}
	body.userViewer .importColors,
	body.userViewer .importColorsIcon,
	body.userViewer .clearColorsIcon,
	body.userViewer .clearColors,
	body.userViewer .colors
	{
		display: none !important;
	}
	div.showPast1 div.past1,
	div.showPast2 div.past2,
	div.showPast3 div.past3,
	div.showPast4 div.past4,
	div.showPast5 div.past5,
	div.showPast6 div.past6,
	div.showPast7 div.past7,
	div.showPast8 div.past8,
	div.showPast9 div.past9
	{
		display: block;
	}

	/*
	div.calendar.searching > #past-weeks
	{
		text-decoration: line-through;
	}
	*//*
	#past-weeks
	{
		margin-left: 0.2%;
	}

	#pastWeeks
	{
		margin-left: 0.5em;
	}

	.archive #past-weeks
	{
		text-decoration: line-through;
	}


	/* today column border *//*
	div.today
	{
		border-color: #FFC800;
	}


	/* higlighted title under cursor *//*
	div.title > input[type="checkbox"]:hover + div.title,
	div.title:hover
	{
		background-color: #ffffd5;
		-webkit-transition: background 0s;
		color: black;
	}

	/* highlight opened entry *//*
	.entry[opened]
	{
		border: 1px solid black;
	}

	div[opened] + div
	{
		border-top: 0;
	}

	.engines input[type="checkbox"]
	{
		width: unset !important;
		vertical-align: top;
	}
	.engines img
	{
		vertical-align: text-bottom !important;
	}

	div.entry
	{
		float: left;
		width: 100%;
	}
	div.entry,
	.pointer,
	.date
	{
		cursor: pointer;
	}

	.filter
	{
		margin-left: 1em;
		cursor: pointer;
	}

	.past,
	.showhide0,
	span[checked] > .checkoff,
	span:not([checked]) > .checkon,
	/*separate showing searies and season premiere*//*
	div.calendar.showNew div.entry:not(.series-premiere):not(.searchResult),
	div.calendar.showReturn div.entry:not(.season-premiere):not(.searchResult)
	{
		display: none;
	}


	/*separate showing searies and season premiere*//*
	#nu-showing,
	#nu-hidden,
	#selected-only-hidden
	{
		display: none !important;
	}

	div.calendar.showNew div.entry.series-premiere:not(.searchResult),
	div.calendar.showReturn div.entry.season-premiere:not(.searchResult)
	{
		display: block;
	}


	/*Search field overlaps text below in Firefox*//*
	#searchFieldContainer
	{
		background-color: unset;
	}


	/*Watched*//*
	body:not(.enableWatched) div.title > input[type="checkbox"]
	{
		display: none;
	}

	body.enableWatched div.entry[watched] > div.title
	{
		text-decoration: line-through;
	}

	div.title > input[type="checkbox"]
	{
		vertical-align: middle;
		margin: 1px 3px 0 1px;
		height: 1em;
	}

	#searchResults div.title > input[type="checkbox"]
	{
		width: unset;
		float: left;
	}

	#searchResults > div.entry:last-child
	{
		margin-bottom: 1em;
	}
	/*Past related*//*
	.past
	{
		opacity: 0.5;
	}

	body.collapseMulti div.day:not(.expand):not(.opened) div.entry.multi
	{
		display: none !important;
	}

	body.collapseMulti div.day:not(.expand):not(.opened) div.entry.multif div.title:after
	{
		content: "";
		background-color: black;
		border-left: 1px solid white;
	}

	body.collapseMulti div.day:not(.expand):not(.opened) div.entry.multif div.title:after
	{
		position: absolute;
		height: 100%;
		right: -1px;
		top: 0;
		width: 3px;
	}
	/*Account popup*//*
	#settings-popup .content h4,
	#manage-links-popup .content h4,
	#account-popup-content .content h4
	{
		margin-top: 1em;
		margin-bottom: 1em;
		display: inline-block;
	}
	#settings-popup .header h4,
	#manage-links-popup .header h4
	{
		margin: 0.2em 0 0 0;
	}
	#settings-popup .content,
	#manage-links-popup .content,
	#account-popup-content .content
	{
		padding-top: 0;
		padding-bottom: 1em;
	}
	#settings-popup-content .content > div > *:first-child,
	#account-popup-content .content > div > *:first-child
	{
		width: 1.6em;
		display: inline-block;
		vertical-align: bottom;
	}

	#settings-popup,
	#manage-links-popup
	{
		position: absolute;
		z-index: 1234;
		top: 50px;
		left: 4.7%;
		width: 1px;
		display: none;
	}
	#settings-popup-content,
	#manage-links-popup-content
	{
		position: absolute;
		top: 0px;
		left: 0px;
		background-color: #ffff00;
		border: 1px dotted black;
		width: 300px;
		min-height: 10px;
	}
	#settings-popup-content div.back,
	#manage-links-popup-content div.back
	{
		font-size: 1.2em;
		width: 1.3em;
		height: 1.3em;
		cursor: pointer;
		position: absolute;
		top: 5px;
		left: 5px;
	}
	.close > svg:first-child
	{
		display: none;
	}
	#settings-popup-content div.close,
	#manage-links-popup-content div.close
	{
		font-size: 1.2em;
		width: 1.3em;
		height: 1.3em;
		cursor: pointer;
		position: absolute;
		top: 0;
		right: 0;
		padding: 5px;
	}
	#settings-popup .header,
	#manage-links-popup .header
	{
		background-color: #7FFFFF;
		padding: 5px;
		text-align: center;
		height: 1.5em;
	}
	#settings-popup .content,
	#manage-links-popup .content,
	#engine-edit
	{
		padding: 3px 10px;
	}
	#engine-edit > div:not(#engine-res),
	#manage-links-popup .content > div:not(#engine-res)
	{
		display: table-row;
		white-space: nowrap;
	}
	#engine-edit > div:not(#engine-res) > *,
	#manage-links-popup .content > div:not(#engine-res) > *
	{
		display: table-cell;
		vertical-align: middle;
		margin: 2px 4px 2px 1px;
	}
	#manage-links-popup .content > div:not(#engine-res) > img
	{
		vertical-align: bottom;
		display: list-item;
	}

	#manage-links-popup .content > div:not(#engine-res) > filter
	{
		padding-left: 0.3em;
	}
	#manage-links-popup .content > div:not(#engine-res) > .edit,
	#manage-links-popup .content > div:not(#engine-res) > .del
	{
		cursor: pointer;
		margin: 3px;
		position: relative;
		top: -0.1em;
		font-size: 80%;
		padding: 3px;
		display: inline-block;
		height: 1em;
		float: left;
	}
	#settings-popup-content div.back:hover,
	#manage-links-popup-content div.back:hover,
	#manage-links-popup .content > div.dragging:not(.hide),
	#manage-links-popup .content:not(.dragging) > div:not(#engine-res):hover
	{
		background-color: #FFFFB7;
		outline: 1px dotted grey;
	}
	.close:hover > svg
	{
		background-color: #e81123;
	}
	.close:hover > svg:last-child
	{
		display: none;
	}
	.close:hover > svg:first-child
	{
		fill: #FFFFFF;
		display: inline-block;
	}

	#manage-links-popup .content > div.dragging.hide > *
	{
		opacity: 0;
	}
	#manage-links-popup .content > div.dragging.hide
	{
		outline: 1px dashed grey;
	}
	#manage-links-popup .content > div:not(.def) > a.link:after
	{
		content: "*";
		text-decoration: none;
		display: inline-block;
		color: red;
		margin-left: 0.2em;
	}
	#engine-edit > div:not(#engine-res) > label
	{
		text-align: right;
	}
	#engine-edit > div:not(#engine-res) > input
	{
		width: 95%;
		margin-left: 0.5em;
		padding-right: 1.5em;
	}
	#engine-edit > div:not(#engine-res) > select
	{
		width: 1.5em;
		position: relative;
		left: -1.8em;
		margin: 0;
		padding: 0;
	}
	#engine-res
	{
		overflow-x: auto;
		overflow-y: hidden;
		min-height: 18px;
		display: block !important;
		margin-left: 0.5em !important;
	}
	#engine-hidden
	{
		display: none !important;
	}
	#engine-res > *
	{
		vertical-align: middle;
		display: inline-block;
		margin: 0 4px 0 0;
	}
	#engine-submit,
	#engine-reset
	{
		font-size: 90%;
		display: inline-block !important;
		width: 50% !important;
	}
	#engine-reset
	{
		margin-left: 1em;
	}
	div.reset
	{
		display: none !important;
	}
	#manage-links-popup[changed] div.reset
	{
		display: block !important;
	}
	#sort-reset
	{
		display: block !important;
		text-align: right;
		margin-right: 0.5em;
		margin-bottom: 0.5em;
	}
	#engine-edit
	{
		 border-top: 1px dotted;
	}
	#manage-links-popup .nu,
	#manage-links-popup .nu
	{
		vertical-align: bottom;
		font-size: 1.3em;
	}
	#manage-links-popup-content .content > div.update
	{
		-webkit-transition:background-color 0.4s ease-in;
		-moz-transition:background-color 0.4s ease-in;
		-o-transition:background-color 0.4s ease-in;
		transition:background-color 0.4s ease-in;
	}

	[draggable]
	{
		-moz-user-select: none;
		-khtml-user-select: none;
		-webkit-user-select: none;
		user-select: none;
		/* Required to make elements draggable in old WebKit *//*
		-khtml-user-drag: element;
		-webkit-user-drag: element;
	}
	[draggable] .dndh
	{
		cursor: move;
		margin: 0 0.5em 0 0 !important;
		font-size: 1.2em;
		float: left;
		position: relative;
		top: -2px;
		padding-left: 3px;
		padding-right: 3px;
	}

	#settings-popup-content > .content > *
	{
		margin: 3px 0 3px 0;
		display: table;
	}

	.user > svg
	{
		margin-right: 0.3em;
	}

/*fixing menu wrapping too soon*//*
	@media screen and (max-width: 1000px)
	{
		body #menu li,
		body:not(.userViewer) #menu li
		{ display: inline-block; }
		body #menu li .nu,
		body:not(.userViewer) #menu li .nu
		{ min-width: unset; }
		body #account-popup,
		body:not(.userViewer) #account-popup
		{ top: 50px; }
	}
	#menu .nu
	{
		font-weight: bold;
	}
	#menu .close
	{
		font-size: 0.9em;
		position: relative;
		top: -0.6em;
		cursor: pointer;
		padding: 0.3em;
	}
	#menu .close > svg
	{
		width: 0.9em;
		height: 0.9em;
		position: unset;
	}

	.user > svg,
	.back > svg,
	.content > div > span > svg
	{
		width: 1.3em;
		height: 1.3em;
		vertical-align: bottom;
	}
	#searchResults > div.entry > div.title,
	body:not(.shortTitle) div > div.entry > div.title,
	body.shortTitle.shortTitleExpand div.day.expand > div.entry > div.title,
	body.shortTitle div.day.opened > div.entry > div.title
	{
		display: flex;
	}
	body.shortTitle:not(.shortTitleExpand) div.day.expand:not(.opened) > div.entry > div.title > input[type="checkbox"],
	body.shortTitle div.day:not(.expand):not(.opened) div.title > input[type="checkbox"]
	{
		float: left;
	}
	body.shortTitle:not(.shortTitleExpand) div.day.expand:not(.opened) > div.entry > div.title,
	body.shortTitle div.day:not(.expand):not(.opened) > div.entry > div.title
	{
		text-overflow: ellipsis;
		white-space: nowrap;
		overflow: hidden;
	}
	div.spacer
	{
		height: 0;
		border-bottom: 1px dotted silver;
		margin-top: 0.5em !important;
		margin-bottom: 0.5em !important;
		display: block !important;
	}
	a.parentheses,
	a.file
	{
		margin-left: 1em;
	}
	a.parentheses:before,
	a.file:before
	{
		text-decoration: none;
		display: inline-block;
		content: "(";
	}
	a.parentheses:after,
	a.file:after
	{
		text-decoration: none;
		display: inline-block;
		content: ")";
	}

	#searchResults > .info
	{
		margin-bottom: 0.7em;
	}
	
	#searchResults > .info > small
	{
		vertical-align: text-bottom;
	}
	#searchResults > .info > small > span:not(.info)
	{
		position: absolute;
		right: 1em;
	}
	span.button
	{
		cursor: pointer;
		background-color: #DDDDDD;
		border-radius: 4px;
		padding: 3px;
	}
	
/* fix search field box covers text on bottom *//*
	#searchFieldContainer
	{
		height: 0;
	}
*/});//css

	style.innerHTML = css;
	$("head").append(style);


	//fix incorrect initial color in colorpicker
	//fix clicking outside of colorpicker saves selected color instead of discarding
	//fix close colorpicker by pressing escape button

	var editingSeriesId = -1;
	var clone = $("#colorPickerHolder").clone();
	$("#colorPickerHolder").remove();
	var picker = clone.colorPicker(
	{
		animationSpeed: 0,
		opacity: false,
		buildCallback: function($elm)
		{
			let cp = this;
			$elm
				.append('<div class="cp-disp"><input type="button" value="save"> <input type="button" value="cancel"></div>')
				.on( "click", "input", function()
				{
					if (!this.value)
						return;

					if (this.value == 'save')
					{
						assignColor( editingSeriesId, "#" + cp.color.colors.HEX, true );
						editingSeriesId = -1;
					}
					cp.toggle();
				});
			$("body").on("keydown", function(e)
			{
	//ESC(27) = cancel
				if (e.which == 27 && $elm.is(":visible"))
					cp.toggle();
			});
		},
		cssAddon: ".cp-disp{ padding-bottom: 2px; clear:both; }",
		renderCallback: function($elm, toggled) {
			var colors = this.color.colors;
			// on show
			if( toggled === true ){
			}
			// on change
			else if( toggled === undefined ){
	//preview new color
				assignColor( editingSeriesId, "#" + colors.HEX, false );
			}
			// on hide
			else if( toggled === false ){
	//restore entry color
				if( editingSeriesId > 0 )
					loadColor( editingSeriesId );

				editingSeriesId = -1;
				picker.detach().appendTo("body");
			}

		}
	}).attr("id", "colorPickerHolderNew"); //replace ID so it won't initialize in main.js

	$("body").off("click", ".picker");

	// now hook up the picker to the picker icons
	$("body").on("click", ".picker", function(e){
		if( !$(e.target).hasClass("picker") ) return;

		editingSeriesId = $(this).parents("[data-series-id]").data("series-id");
	//set initial color in colorpicker based on current entry or default to white
		picker.val(coalesce(DB.savedColors[editingSeriesId], "#ffffff"));
		picker.detach().appendTo(this).click();
	});

	function middleClick(e, search)
	{
		if (e.button != 1 && !(!e.button && e.ctrlKey) )
			return;

		e.stopPropagation();
		e.preventDefault();
		let parent,
				entry = true;
		if (search)
			parent = $(search);
		else if ($(this).is("div.title"))
			parent = $(this).parent();
		else
		{
			parent = $(this).parent().find("div.entry");
			entry = false;
		}
		let func = function(e)
		{
			let el = $(this),
					MONKEY_ID = encodeURIComponent( el.data("series-id") );
			if (!entry && !DB.getColor(MONKEY_ID))
				return;

	//		let title = el.children("div.title").text().replace("?", "").replace(/[0-9]+-[0-9]+-[0-9]+/, ""),
			let title = this._title && this._title._titleOrig ? this._title._titleOrig : el.children("div.title").text();
			title = title.replace("?", "").replace(/[0-9]+-[0-9]+-[0-9]+/, "");
	//				MONKEY = encodeURIComponent( title ),
			let MONKEY = encodeURIComponent( title.replace(/ E[0-9]+/g, "") ),
					MONKEY_N = encodeURIComponent( title.replace( /S[0-9]+E[0-9]+$/g, '' ) ),
					WIKI_TITLE = encodeURIComponent( el.data("series-source") );
			$.each( _engines, function( i, engine )
			{
				if (!$("body").hasClass("engine_" + cleanName(engine.host)))
					return;

				let href = engine.href
					.replace( "MONKEY_ID", MONKEY_ID )
					.replace( "MONKEY_N", MONKEY_N )
					.replace( "MONKEY", MONKEY )
					.replace( "{WIKI_TITLE}", WIKI_TITLE );

				href = fixLink(href, engine.name);
				window.open(href, (MONKEY + engine.name).replace(/ /g, "").replace(/%.{2}/g, ""));
			});
		};
		parent.each(func);
	}
	$("body").on("mousedown", "div.date,div.title", middleClick);

	let _markSearchResults = markSearchResults;
	window.markSearchResults = function markSearchResults()
	{
		if (showMyShows.box || showMyHidden.box)
			return

		let entries = $("#searchResults").find("div.entry");
		entries.each(watched.attach);
		setTimeout(function()
		{
			$("div.day").each(collapseMulti);
		});

		return _markSearchResults();
	};

	$("body").on("click", 'div.entry div.title>input[type="checkbox"]', function(e)
	{
		e.stopPropagation();
	});
	//sanitizing engine links
	$("body").on("click", "div.entry div.title", function(e)
	{
		if (e.isTrigger && !force)
			return;

		force = false;
		let obj = this;
		setTimeout(function()
		{
			let details = $(obj).parent().find(".details");
			if (!details.length || details[0].inited)
				return;

			details[0].inited = true;
			let showHideObj = document.createElement("a"),
					showId = $(obj.parentNode).attr("data-series-id"),
					show = document.createElement("span"),
					hide = document.createElement("span");

			show.innerHTML = "Show";
			show.className = "showhide0";
			hide.innerHTML = "Hide";
			hide.className = "showhide1";
			showHideObj.appendChild(show);
			showHideObj.appendChild(hide);
			showHideObj.appendChild(document.createTextNode(" this show"));

			showHideObj.className = "showhide";
			showHideObj.href = "#";
			showHideObj.addEventListener("click", function(e)
			{
				e.stopPropagation();
				e.preventDefault();
				showHide(parseInt(showId), 2);
			}, false);

			let list = $(obj).parent().find(".engines").append(showHideObj).children();
			for (let i = 0; i < list.length; i += 3)
			{
				let img = list[i],
						a = list[i+1],
						br = list[i+2],
						checkbox = document.createElement("input"),
						engine = window.engines[i/3] ? window.engines[i/3].host : img.src ? img.src.match(/\?domain=(.*)/)[1] : null,
						id = "engine_" + cleanName(engine),
						engineInfo = window.engines[enginesFind(engine)],
						domain = engineInfo ? getHost(engineInfo.href) : null;

				if (domain)
					img.src = "http://www.google.com/s2/favicons?domain=" + domain;

				$(img).toggleClass(id, true);
				$(a).toggleClass(id, true);
				$(br).toggleClass(id, true);
				$(checkbox).toggleClass(id, true);
				checkbox.engine = engine;
				checkbox.type = "checkbox";
				checkbox.title = "Open with middle click on title";
				checkbox.checked = enginesCheck(engine) != -1;
				img.parentNode.insertBefore(checkbox, img);
				if (a.className.indexOf("archive-link") != -1 && (showMyShows.box || showMyHidden.box))
				{
					$(a).toggleClass("archive-link", false);
					a.textContent = "Show all episodes";
					a.href = "javascript:search('info:" + showId + "');";
				}
				if (engine == "airdates.tv" || a.className == "showhide")
				{
					checkbox.style.visibility = "hidden";
					return;
				}
				a.href = fixLink(a.href, a.text);

				$(checkbox).on("click", "", function(e)
				{
					if (checkbox.checked)
						enginesAdd(checkbox.engine);
					else
						enginesRemove(checkbox.engine);

					$("input." + id).prop("checked", checkbox.checked);
				});

			};
		});
	});//$("body").on("click", "div.entry div.title", function(e)

	function fixLink(link, engine)
	{
		link = link.replace("%3F", "").replace(/[0-9]+-[0-9]+-[0-9]+(%20)?/, "").replace(/( |%20)E[0-9]+/, "");
		if (engine == "Piratebay")
			link = link.replace(/['"`!]/g, '');
		return link;
	}

	function showHideLoad()
	{

		if (showHideLoad.inited)
			return;

		$(".days").before(createCheckbox("showHidden", "Show hidden", Settings.prefs.showHidden ? true : false, Settings.callback));
		$(".days").before(createCheckbox("collapseMulti", "Collapse multiple", Settings.prefs.collapseMulti ? true : false, collapseMulti.onOff));
		for(let i = 0; i < _hidden.length; i++)
		{
			showHide(_hidden[i], 1);
		}
		showHideLoad.inited = true;


		let clearColors = $(".clearColors"),
				clearHidden = clearColors.clone(false),
				clearWatched = clearColors.clone(false);

		clearHidden.removeClass();
		clearHidden.addClass("clearHidden");
		clearHidden.html("Clear hidden");
		clearHidden.insertAfter(clearColors);
		clearWatched.removeClass();
		clearWatched.addClass("clearWatched");
		clearWatched.html("Clear watched");
		clearWatched.insertAfter(clearHidden);
		clearColors.after(" | ");
		clearHidden.after(" | ");
		clearHidden.on( "click", function()
		{
			let array = [];
			for(let i = 0; i < _hidden.length; i++)
				array.push(_hidden[i]);

			for(let i = 0; i < array.length; i++)
				showHide(array[i], 0);

			alert( "Done!" );
			return false;
		});
		clearWatched.on( "click", function()
		{
			watched._list = {};
			watched.save();
			$("div.entry").each(function(i, entry)
			{
				if (entry._input)
					watched.update(entry, false);
			});

			alert( "Done!" );
			return false;
		});
			$("body").off("click", ".exportColors");
			$("body").on( "click", ".exportColors", function(e)
			{
				e.stopImmediatePropagation();
				let str = exportGetColors();
				if (str)
						prompt( "This is the crazy text. \nYou can save it in a normal textfile and/or import it to another computer/browser.", str );
				else
						alert("Nothing to export");
				return false;
			});
	} //showHideLoad()
	DB.viewing = DB.username != DB.loggedInUsername;
	let ul = $("#menu").find("ul");
	if (DB.viewing)
	{
		ul.children("li:last-child").css("margin-right", "1.5em");
		let li = $(multiline(function(){/*
<li>Viewing as 
	<span class="user">
		<svg viewBox="0 0 24 24">
			<path d="M12,4A4,4 0 0,1 16,8A4,4 0 0,1 12,12A4,4 0 0,1 8,8A4,4 0 0,1 12,4M12,14C16.42,14 20,15.79 20,18V20H4V18C4,15.79 7.58,14 12,14Z"></path>
		</svg>
	</span>
	<span class="nu"></span>
	<a class="close" href="*/}) + window.location.href.replace(/\/u\/[^?#]+/, "") + multiline(function(){/*">
		<svg viewBox="0 0 24 24">
			<path d="M19,3H16.3H7.7H5A2,2 0 0,0 3,5V7.7V16.4V19A2,2 0 0,0 5,21H7.7H16.4H19A2,2 0 0,0 21,19V16.3V7.7V5A2,2 0 0,0 19,3M15.6,17L12,13.4L8.4,17L7,15.6L10.6,12L7,8.4L8.4,7L12,10.6L15.6,7L17,8.4L13.4,12L17,15.6L15.6,17Z"></path>
		</svg>
		<svg viewBox="0 0 24 24">
			<path d="M19,3H5A2,2 0 0,0 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5A2,2 0 0,0 19,3M19,19H5V5H19V19M17,8.4L13.4,12L17,15.6L15.6,17L12,13.4L8.4,17L7,15.6L10.6,12L7,8.4L8.4,7L12,10.6L15.6,7L17,8.4Z"></path>
		</svg>
	</a>
</li>
*/})).appendTo(ul);
		li.find("span.nu").text(DB.username);
//fix auto wrap on small screen
		let width = li.prop("clientWidth");
		width = Math.round(width * 2 + 760 + width / 6);
		$("head").append("<style>@media screen and (max-width: " + width + multiline(function(){/*
px)
{
	body.userViewer #menu li:not(:nth-last-child(2)):not(:last-child){ display: block; }
	body.userViewer #menu li .nu{ min-width: 15px; }
	body.userViewer #account-popup,
	body.userViewer #settings-popup,
	body.userViewer #manage-links-popup
	{ top: 80px; }
}
</style>*/}));
	}
	else
	{
		setTimeout(function()
		{
		let li = ul.children().last();
		let width = li.prop("clientWidth");
		width = Math.round(width * 2 + 600 + width / 6);
		$("head").append("<style>@media screen and (max-width: " + width + multiline(function(){/*
px)
{
	body:not(.userViewer) #menu li{ display: block; }
	body:not(.userViewer) #menu li .nu{ min-width: 15px; }
	body:not(.userViewer) #account-popup,
	body:not(.userViewer) #settings-popup,
	body:not(.userViewer) #manage-links-popup
	{ top: 80px; }
}
</style>*/}));
});
	}


	//fix when removing color it still saves it in database as #FFFFFF
	window.DB._setColor = window.DB.setColor;
	window.DB.setColor = function setColor(id, c)
	{
		if (c == "#FFFFFF")
			c = "";

		if (c)
			DB.infoAdd(id);
		else if (_hidden.indexOf(id) == -1)
			DB.infoRemove(id);
		if (showMyShows.box)
			showMyShows();
		else if (showMyHidden.box)
		{
			showMyHidden();
		}

		this._setColor(id, c);
	};

	//hiding old combined checkboxes
	$( "#nu-showing" ).toggle(false);
	$( "#nu-hidden" ).toggle(false);
	//add new separate checkboxes
	createCheckbox("showNew", "New shows", Settings.prefs.showNew ? true : false, Settings.callback);
	createCheckbox("showReturn", "Returning shows", Settings.prefs.showReturn ? true : false, Settings.callback);

	//replacing existing "my shows" checkboxes with ours
	let _toggleSelectedOnly = window.toggleSelectedOnly,
			_updateSelectedOnly = window.updateSelectedOnly;

	window.toggleSelectedOnly = function(){};
	window.updateSelectedOnly = function(){};
	$("#selected-only-showing").toggle(false);
	$("#selected-only-hidden").toggle(false);
	createCheckbox("activeOnly", (DB.viewing ? DB.username + " user's" : "My") + " shows", "s", function(e, id, checked){}, [$("#selected-only-hidden").prop("title")]);

	//fix auto clear search field on click
	setTimeout(function()
	{
		$(document).off("click", ".onX, .x").on('touchstart click', '.onX', function( ev )
		{
			ev.preventDefault();
			$(this).removeClass('x onX').val('').change();
		});
	//fix no X button after page refresh and browser auto fill search bar with previous text
		$('input.clearable').trigger("input");
	});



	//injecting userscript function execution
		showPast(function()
		{
	//adding watched checkboxes
			$("div.day > div.entry").each(watched.attach);
	//collapse multiple entries of the same series in one day
			$("div.day").each(collapseMulti);
		});
		showHideLoad();

	//list of user's shows
	DB.infoNameClean = function(entry)
	{
		let title = entry._title && entry._title._titleOrig ? entry._title._titleOrig : $(entry).find("div.title").text();
		return title.substring(0, title.lastIndexOf(" "));
	};

	DB.infoSave = function()
	{
		ls("info", DB.info);
	};

	DB.infoAdd = function(id, name, nosave)
	{
		if (typeof(name) == "undefined")
		{
			return DB.infoAdd(id, DB.infoGet(id), nosave);
		}
		else if (!name)
		{
			setTimeout(function()
			{
				DB.infoLoad(id);
			}, rand(100, 2000));
			return;
		}
		DB.info[id] = name;
		if (!nosave)
			DB.infoSave();
	};

	DB.infoRemove = function(id)
	{
		delete DB.info[id];
		DB.infoSave();
	};

	DB.infoGet = function(id)
	{
		let entry = $('div.days div[data-series-id="' + id + '"]').first()[0];
		if (entry)
			return [DB.infoNameClean(entry), entry.getAttribute("data-series-source")];

		return null;
	};

	DB.infoLoad = function(id)
	{
		let obj = document.createElement("div");
		$(obj).load("/s?"+$.param({q:"info:" + id}), function(e)
		{
			let title = $(obj).find("b").first().text();
			title = title.substring(0, title.lastIndexOf("(") - 1);
			if (title)
				DB.infoAdd(id, [title, $(obj).find(".entry").attr("data-series-source")]);
		});
	};

	function showMyShows(e)
	{
		if (!DB.infoLoaded)
		{
			setTimeout(showMyShows, 100);
			return;
		}
		$(".entry").removeClass("searchResult");
		$("#searchStatus").css("visibility","hidden");
		let list = [];

		for (let i in DB.savedColors)
		{
			if (!DB.info[i])
				continue;

//http://runtime-era.blogspot.com/2011/11/grouping-html-hex-colors-by-hue-in.html
			/* Get the hex value without hash symbol. */
			let hex = DB.savedColors[i].substring(1);
			/* Get the RGB values to calculate the Hue. */
			let r = parseInt(hex.substring(0,2),16)/255,
					g = parseInt(hex.substring(2,4),16)/255,
					b = parseInt(hex.substring(4,6),16)/255;

			/* Getting the Max and Min values for Chroma. */
			let max = Math.max.apply(Math, [r,g,b]),
					min = Math.min.apply(Math, [r,g,b]);

			/* Variables for HSV value of hex color. */
			let chr = max-min,
					hue = 0,
					val = max,
					sat = 0;

			if (val > 0)
			{
				/* Calculate Saturation only if Value isn't 0. */
				sat = chr/val;
				if (sat > 0)
				{
					if (r == max)
					{ 
						hue = 60 * (((g - min) - (b - min)) / chr);
						if (hue < 0)
							hue += 360;
					}
					else if (g == max)
					{ 
						hue = 120 + 60 * (((b - min) - (r - min)) / chr); 
					} else if (b == max)
					{ 
						hue = 240 + 60 * (((r - min) - (g - min)) / chr); 
					}
				}
			}
			
			/* Modifies existing objects by adding HSV values. */
			list[list.length] = {
				id: i,
				hex: hex,
				hue: hue,
				sat: sat,
				val: val,
				lum: (r * 299 + g * 587 + b * 114) / 1000
			}
		}
		(function display()
		{
			if (Settings.prefs.sortBy == Settings.SORT_COLOR)
			{
				list = list.sort(function(a,b)
				{
					let r = b.hue - a.hue;
					if (!r)
						r = b.val - a.val;
					if (!r)
						r = b.sat - a.sat;
					if (!r)
						r = DB.info[b.id][0].toLowerCase().localeCompare(DB.info[a.id][0].toLowerCase());
					return r;
				});
			}
			else
			{
				list = list.sort(function(a, b)
				{
					return DB.info[a.id][0].toLowerCase().localeCompare(DB.info[b.id][0].toLowerCase());
				});
			}
			$(showMyShows.box).find("span.button").off("click");
			showMyShows.box = document.createElement("div");
			let entry = document.createElement("div"),
					title = document.createElement("div"),
					count = 0;

			entry.appendChild(title);
			entry.className = "entry";
			title.className = "title";
			for(let i = 0; i < list.length; i++)
			{
				let id = list[i].id;

				count++;
				entry = entry.cloneNode(true);
				title = entry.firstChild;
				entry.setAttribute("data-series-id", id);
				entry.setAttribute("data-series-source", DB.info[id][1]);
				title.textContent = DB.info[id][0];
				showMyShows.box.appendChild(entry);
			}
			let text = "You don't have any shows";
		
			if (count)
			{
				function getSortName()
				{
					let a = ["Name", "Color"];
					return  a[Settings.prefs.sortBy + 1] || a[0];
				}
				text = (DB.viewing ? DB.username + " has " : "You have ") + count + " show" + (count > 1 ? "s" : "") + '. <span>Sort by <span class="button">' + getSortName() + "</span></span>";
			}
			$(showMyShows.box).prepend('<div class="info"><small>' + text + '</small><div>');
			$("#searchResults").html(showMyShows.box.innerHTML).find("span.button").click(function(e)
			{
				if (++Settings.prefs.sortBy > 1)
					Settings.prefs.sortBy = 0;
				
				Settings.save();
				display();
			});;
		})();
	}

	function showMyHidden(e)
	{
		if (!DB.infoLoaded)
		{
			setTimeout(showMyHidden, 100);
			return;
		}
		$(".entry").removeClass("searchResult");
		$("#searchStatus").css("visibility","hidden");
		showMyHidden.box = document.createElement("div");
		let entry = document.createElement("div"),
				title = document.createElement("div");

		entry.appendChild(title);
		entry.className = "entry";
		title.className = "title";
		let list = [],
				count = 0;

		for(let i = 0; i < _hidden.length; i++)
		{
			list[list.length] = _hidden[i];
		}
		list.sort(function(a, b)
		{
			return !DB.info[a] || !DB.info[b] ? -1 : DB.info[a][0].toLowerCase().localeCompare(DB.info[b][0].toLowerCase());
		});
		for(let i = 0; i < list.length; i++)
		{
			let id = list[i];
			if (!DB.info[id])
				continue;

			count++;
			entry = entry.cloneNode(true);
			title = entry.firstChild;
			entry.setAttribute("data-series-id", id);
			entry.setAttribute("data-series-source", DB.info[id][1]);
			title.textContent = DB.info[id][0];
			showMyHidden.box.appendChild(entry);
		}
		let text = "There are no hidden shows";
		if (count)
		{
			text = "There are " + count + " hidden show" + (count > 1 ? "s" : "") + ":";
		}
		$(showMyHidden.box).prepend('<small>' + text + '</small><div style="height: 0.5em;"></div>');
		$("#searchResults").html(showMyHidden.box.innerHTML);
	}
	$(document).ready(function()
	{
		function hideNode(id)
		{
			$("." + id).each(function(i, e)
			{
				let prev = e.previousSibling;
				if (prev.nodeType == prev.TEXT_NODE)
				{
					let span = document.createElement("span");
					prev.parentNode.insertBefore(span, prev);
					span.appendChild(prev);
					prev = span;
				}
				$(prev).toggleClass(id + "Icon", true)
			});
		}
		if (DB.viewing)
		{
			$("body").toggleClass("userViewer", true);
			hideNode("clearColors");
			hideNode("importColors");
		}
		let accountLoop = 50;
		$("#account-popup").attr("hidden", "");
		$("#account-overview").click(function(e)
		{
			if (e.isTrigger)
				return;

			Settings.hide();
			customLinks.hide();
		});
		$("#account-overview").click(function loop(e)
		{
			if (e.isTrigger)
				return;

			Settings.hide();
			customLinks.hide();
			$("#account-popup").removeAttr("hidden");
			let as = $("#account-popup-content .content a");
			if( !$( "#account-popup" ).hasClass("loaded") || (!as.length && accountLoop--))
				return setTimeout(function()
				{
					loop(e)
				}, 100);

			if (!as.length)
				return;

			let header = $("#account-popup-content").find("div.header");
			//account reset password
			if (DB.loggedInUsername)
			{
				let div = $("<div/>").html(header.html().replace(/(\s)+/g, "$1")),
//						a = $('<a href="/_u/forgot-password#' + DB.username +'">Reset password</a>');
						a = $('<a href="/_u/forgot-password">Reset password</a>');
				header.html("").append(div);
				div.find("a").after(a).after(" | ");
			}
			let content = $("#account-popup-content").find("div.content");
			//account overview neat icons
			content.contents().filter(function()
			{
				if (this.tagName == "BR")
					this.parentNode.removeChild(this);

				if (this.nodeType != Node.TEXT_NODE || !this.textContent.trim())
					return;

				let span = document.createElement("span"),
						div = document.createElement("div");
				div.appendChild(span);
				div.appendChild(this.nextSibling);
				span.textContent = this.textContent.trim();
				this.parentNode.replaceChild(div, this);
			});

			$("#account-overview").unbind("click", loop);
			content.find("div:first-of-type > span").html('<svg viewBox="0 0 24 24"><path d="M10.59,13.41C11,13.8 11,14.44 10.59,14.83C10.2,15.22 9.56,15.22 9.17,14.83C7.22,12.88 7.22,9.71 9.17,7.76V7.76L12.71,4.22C14.66,2.27 17.83,2.27 19.78,4.22C21.73,6.17 21.73,9.34 19.78,11.29L18.29,12.78C18.3,11.96 18.17,11.14 17.89,10.36L18.36,9.88C19.54,8.71 19.54,6.81 18.36,5.64C17.19,4.46 15.29,4.46 14.12,5.64L10.59,9.17C9.41,10.34 9.41,12.24 10.59,13.41M13.41,9.17C13.8,8.78 14.44,8.78 14.83,9.17C16.78,11.12 16.78,14.29 14.83,16.24V16.24L11.29,19.78C9.34,21.73 6.17,21.73 4.22,19.78C2.27,17.83 2.27,14.66 4.22,12.71L5.71,11.22C5.7,12.04 5.83,12.86 6.11,13.65L5.64,14.12C4.46,15.29 4.46,17.19 5.64,18.36C6.81,19.54 8.71,19.54 9.88,18.36L13.41,14.83C14.59,13.66 14.59,11.76 13.41,10.59C13,10.2 13,9.56 13.41,9.17Z"></path></svg>');
			let d = document.createElement("a");
			d.addEventListener("click", function(e)
			{
				if (e.isTrigger)
					return;

				e.preventDefault();
				e.stopPropagation();

				let data = exportGetColors(),
						d = new Date(),
						date = d.getFullYear() + pad(d.getMonth()+1) + pad(d.getDate()) + pad(d.getHours()) + pad(d.getMinutes()) + pad(d.getSeconds());
				if (data)
					fileSave("Airdates.tv_colors_" + (DB.username ? DB.username.replace(/[\/\\?%*:|"<>]/g, "_") + "_" : "") + date + ".txt", data);
				else
					alert("Nothing to export");
			}, false);
			d.textContent = "save to file";
			d.className = "file";
			content.find(".exportColors").append(d);
			d = d.cloneNode(true);
			d.addEventListener("click", function(e)
			{
				if (e.isTrigger)
					return;

				e.preventDefault();
				e.stopPropagation();

				fileLoad(function(str)
				{
					if (str)
					{
						$.each( str.split( ";" ), function( i, e ){
							assignColor.apply( null, e.split("=").concat([true] ) );
						} );
						alert( "kk, imported " + str.split(";").length + " colors" );
					}
					else
					{
						alert( "Error importing" );
					}
				}, ".txt");

			}, false);
			d.textContent = "load from file";
			content.find(".importColors").append(d);

			hideNode("importColors");
			let a = document.createElement("a"),
					i = document.createElement("span"),
					span = document.createElement("div"),
					h = document.createElement("h4"),
					item = span,
					parent = as[as.length-1].parentNode.parentNode;

			h.textContent = adeName + " v" + adeVersion;
			parent.appendChild(h);
			span.appendChild(i);
			span.appendChild(a);

			span = span.cloneNode(true);
			a = span.lastChild;
			i = span.firstChild;
			a.className = "";
			i.innerHTML = '<svg viewBox="0 0 24 24"><path d="M9.5,3A6.5,6.5 0 0,1 16,9.5C16,11.11 15.41,12.59 14.44,13.73L14.71,14H15.5L20.5,19L19,20.5L14,15.5V14.71L13.73,14.44C12.59,15.41 11.11,16 9.5,16A6.5,6.5 0 0,1 3,9.5A6.5,6.5 0 0,1 9.5,3M9.5,5C7,5 5,7 5,9.5C5,12 7,14 9.5,14C12,14 14,12 14,9.5C14,7 12,5 9.5,5Z" /></svg>';
			a.href = '#myshows';
			a.id = "";
			a.addEventListener("click", function(e)
			{
				e.preventDefault();
				search("info:myshows");
				$("#account-popup").toggle(false);
			}, false);
			a.textContent = (DB.viewing ? DB.username + " user's" : "My") + " shows";
			parent.appendChild(span);

			span = span.cloneNode(true);
			a = span.lastChild;
			i = span.firstChild;
			i.innerHTML = '<svg viewBox="0 0 24 24"><path d="M9.5,3A6.5,6.5 0 0,1 16,9.5C16,11.11 15.41,12.59 14.44,13.73L14.71,14H15.5L20.5,19L19,20.5L14,15.5V14.71L13.73,14.44C12.59,15.41 11.11,16 9.5,16A6.5,6.5 0 0,1 3,9.5A6.5,6.5 0 0,1 9.5,3M9.5,5C7,5 5,7 5,9.5C5,12 7,14 9.5,14C12,14 14,12 14,9.5C14,7 12,5 9.5,5Z" /></svg>';
			a.href = '#hidden';
			a.id = "";
			a.addEventListener("click", function(e)
			{
				e.preventDefault();
				search("info:hidden");
				$("#account-popup").toggle(false);
			}, false);
			a.textContent = "Hidden shows";
			parent.appendChild(span);

			span = span.cloneNode(true);
			a = span.lastChild;
			i = span.firstChild;
			i.innerHTML = '<svg viewBox="0 0 24 24"><path d="M3,5H9V11H3V5M5,7V9H7V7H5M11,7H21V9H11V7M11,15H21V17H11V15M5,20L1.5,16.5L2.91,15.09L5,17.17L9.59,12.59L11,14L5,20Z" /></svg>';
			a.href = '#';
			a.id = "manage-links-open";
			a.addEventListener("click", function(e)
			{
				e.preventDefault();
				customLinks.manager(function()
				{
					customLinks.show();
					$("#account-popup").toggle(false);
				});

			}, false);
			a.textContent = "Links manager";
			parent.appendChild(span);

			span = span.cloneNode(true);
			a = span.lastChild;
			i = span.firstChild;
			i.innerHTML = '<svg viewBox="0 0 24 24"><path d="M3,17V19H9V17H3M3,5V7H13V5H3M13,21V19H21V17H13V15H11V21H13M7,9V11H3V13H7V15H9V9H7M21,13V11H11V13H21M15,9H17V7H21V5H17V3H15V9Z" /></svg>';
			a.href = '#';
			a.id = "settings-open";
			a.addEventListener("click", function(e)
			{
				e.preventDefault();
				Settings.show();
				$("#account-popup").toggle(false);
			}, false);
			a.textContent = "Options";
			parent.appendChild(span);

			a = document.createElement("a");
			a.href = "https://github.com/vanowm/airdates.tv_enhancer/issues";
			a.target = "_blank";
			a.textContent = "Support";
			a.className = "parentheses support";
			parent.insertBefore(a, h.nextSibling);

		});

		let repeat = 100,
				list = ls("info") || {},
				userCookie = readCookieRaw("adsc_SESSION"),
				isUser = userCookie && userCookie.indexOf("username=") > 0,
				blank = {};
		DB.info = {};
		DB.infoLoaded = false;
		//to avoid hit a ceiling of max data allowed store in local storage, we only save names of user's current shows, nothing else.
		//unfortunately we don't know when saved colors are done loading for registered users, so we must wait in a loop
		(function loop()
		{
			let added = false;
			for(let id in DB.savedColors)
			{
				DB.loaded = true;
				repeat = 0;
				let col = new Colors().setColor(DB.savedColors[id]);

 				//there is a bug in original ADT that store show's color as "FFFFFF" (which is "delete" show color)
				if (col.HEX == "FFFFFF")
					assignColor(id, DB.savedColors[id], true);

				if (id in list)
				{
					DB.info[id] = list[id];
					continue;
				}
				added = true;
				DB.infoAdd(id);
			}
			//we know DB.savedColors is empty, we can set it to empty again within our namespace so we can see if it was changed
			if (repeat == 100 && !Object.keys(DB.savedColors).length)
				DB.savedColors = blank;

			if (isUser && repeat-- && DB.savedColors === blank)
				return setTimeout(loop, 100);


			for(let i = 0; i < _hidden.length; i++)
			{
				let id = _hidden[i];
				if (id in list)
				{
					DB.info[id] = list[id];
					continue;
				}
				added = true;
				DB.infoAdd(id);
			}

			DB.infoLoaded = true;
			if (added)
				DB.infoSave();

			
		})();

	//fix paste via right click: adding input event
		$( "#searchBecauseNoOneChecks" ).on( "input keyup change search", function(e)
		{
			let q = this.value.trim();
			if (q == "info:myshows" || q.match(/^info:([a-zA-Z]+|$)/))
			{
				e.preventDefault();
				e.stopPropagation();
				if (q == "info:hidden")
					showMyHidden(e);
				else if (q == "info:myshows")
					showMyShows(e);
				else
				{
					showMyShows.box = showMyHidden.box = document.createElement("div");
					$("#searchResults").html('<ul id="resultsBecauseNoOneChecks"><li>No results :(</li></ul><small>Search took 0.000 seconds</small>');
				}
	//fix paste via right click
				if (e.type == "input")
					$(this).trigger("change");
			}
			else
			{
				showMyShows.box = null;
				showMyHidden.box = null;
			}

		}).trigger("change");

		//fix clear colors for members
		$(document.body).off( "click", ".clearColors");
		$(document.body).on( "click", ".clearColors", function(e)
		{
			e.stopPropagation();
			e.preventDefault();
			if (!DB.viewing)
			{
				$.each( DB.savedColors, function( i, c )
				{ 
					assignColor( i, null, true );
				} );
				alert( "Done!" ); 
			}
			else
				alert( "You don't have permission!" );

			return false; 
		});


	});//document.ready()

	$(document.body).on( "click touchstart", function(e)
	{
		if (e.isTrigger)
			return;

		let close = $(e.target).parents(".close").get().length,
				p = $( e.target ).parents("#manage-links-popup").get().length;

		if (e.target.id != "manage-links-open" && (p == 0 || (p && close)))
			customLinks.hide();

		p = $( e.target ).parents("#settings-popup").get().length;
		if (e.target.id != "settings-open" && (p == 0 || (p && close)))
			Settings.hide();
	});
	//reset password auto fill username
	if (location.pathname == "/_u/forgot-password")
		$("#username").val(DB.loggedInUsername);

	$(window).on("hashchange", function(e)
	{
		if (location.hash == "#myshows")
			search("info:myshows");
		else if (location.hash == "#hidden")
			search("info:hidden");

	}).trigger("hashchange");

};//func()

//disqus
if (window.top !== window.self)
{
	func = function(){};

//disqus troll filter
	if (window.location.href.indexOf("disqus.com") != -1)
	{
		let trollHide = false;
		let trollList = ls("trolls"),
				trollTimer,
				comments = {};

		if (!trollList || typeof(trollList) != "object")
			trollList = ["Tubasing"];

		let isTroll = function (name)
		{
			return trollList.indexOf(name);
		};

		let trollSave = function ()
		{
			clearTimeout(trollTimer);
			trollTimer = setTimeout(function()
			{
				ls("trolls", trollList);
			}, 1000);
		};

		let trollAdd = function (name)
		{
			if (isTroll(name) == -1)
				trollList.push(name);

			trollSave();
		};

		let trollRemove = function (name)
		{
			let n = isTroll(name);
			if (n != -1)
				trollList.splice(n, 1);

			trollSave();
		};

		let isMatch = function (needle, array)
		{
			let r = -1;
			for(let i = 0; i < array.length; i++)
			{
				r = needle.indexOf(array[i]);
				if (r != -1)
					break;
			}
			return r;
		};
		let findParent = function (obj, c)
		{
			if (typeof(c) != "object")
				c = [c];

			if (obj && obj.className && isMatch(obj.className, c) != -1)
				return obj;

			if (obj)
				return findParent(obj.parentNode, c);

			return null;
		};
		let censor = function (a, b, c, d, e)
		{
			let p = "blah",
					r = "",
					caps = true,
					t,
					i,
					isStr = isNaN(a.replace(/['`].*/, ''));

			if ((a.length < 2 && isStr) || (a.length < 7 && a.match(/['`]/) && isStr) || a.match(/^\$?[0-9]+k?/i))
				return a;

			for(i = 0; i < a.length; i++)
				if (a[i] == a[i].toLowerCase())
				{
					caps = false;
					break;
				}

			for(i = 0; i < p.length; i++)
			{
				t = p[i];

				if (a.length < i + 1)
					continue;

				if (caps || (a.length > i && a[i] != a[i].toLowerCase()))
					t = t.toUpperCase();

				r += t;
			}
			return r;
		};

		let toggleTroll = function (comment, f)
		{
			//f = 0: orig
			//f = 1: troll
			//f = 2: toggle
			f = typeof(f) == "undefined" ? 2 : f;
			let parent = comment._parent,
					t = true;
			if (f == 1 || (f == 2 && parent.getAttribute("troll") != "true"))
			{
				if (trollHide)
					comment.innerHTML = '<img src="' + trollSrc + '" class="trollComment">';
				else
					censorText(comment);
			}
			else
			{
				censorText(comment, true);
				t = false;
			}
			parent.setAttribute("troll", t);
			return t;
		};

		let censorText = function (obj, orig)
		{
			let c = obj.childNodes;
			for(let i = 0; i < c.length; i++)
			{
				if (c[i].nodeName == "#text")
				{
					if (!("nodeValueOrig" in c[i]))
						c[i].nodeValueOrig = c[i].nodeValue;

					let t;
					if (orig)
						t = c[i].nodeValueOrig;
					else
					{
						if (!("nodeValueTroll" in c[i]))
							c[i].nodeValueTroll = c[i].nodeValue.replace(/(\w+(['`]\w+)?)/g, censor);

						t = c[i].nodeValueTroll;
					}

					c[i].nodeValue = t;
				}
				else if (c[i].childNodes.length && c[i].className != "see-more")
					censorText(c[i], orig);
			}
			return obj.innerHTML;
		};

		window.addEventListener("load", function(e)
		{
			let timer = setInterval (function()
			{
				let posts = document.getElementById("post-list");
				if (!posts)
					return;

				clearInterval(timer);
				timer = setInterval (function()
				{
					let names = posts.getElementsByClassName("author");
					if (!names.length)
						return;
					clearInterval(timer);

					let style = document.createElement("style");
					style.innerHTML = multiline(function(){/*
.trollComment
{
	cursor: pointer;
	opacity: 0.4;
	transform: scaleX(-1)
}
.post-byline:not([troll="true"]) img.troll
{
	opacity: 0.1;
	transform: scaleX(-1);
}
img.troll
{
	background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAA3NCSVQICAjb4U/gAAAACXBIWXMAAAsSAAALEgHS3X78AAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M1cbXjNgAAABZ0RVh0Q3JlYXRpb24gVGltZQAxMi8yOC8xMZSAjI8AAAA/UExURf///wAAAAEBAQICAgMDAwQEBAUFBQYGBgcHBwgICAkJCQoKCgsLCw0NDQ8PDxAQEBISEhMTExYWFvr6+v////L9RbYAAAABdFJOUwBA5thmAAAAZklEQVQYGY3BWw6CMABFwXtQKLZafJz9r1WaaPgycSb5wwys8KT1DFcPZIeHlgQBZ5jcbUnTByq4oDXpopMDd88JWlCZEEtSKUsHRCUJr1W8iVqTIBeWAirZ4Rdk6A6cWPMBHfLbGzqjB8v8i7F/AAAAAElFTkSuQmCC");
	width: 16px;
	height: 16px;
	cursor: pointer;
	margin-left: 0.3em;
	vertical-align: top;
	display: inline-block;
}
.trollMenuImg
{
	vertical-align: top;
}
.trollBox
{
	height: auto;
	line-height: 1.3em;
}
*/
					});
					document.getElementsByTagName("head")[0].appendChild(style);
					for(let i = 0; i < names.length; i++)
					{

						let body = findParent(names[i], "post-content");
						if (!body)
							continue;

						let parent = findParent(names[i], "post-byline"),
								img = document.createElement("img"),
								name = names[i].innerText,
								troll = (isTroll(name) != -1),
								post = body.getElementsByClassName("post-message")[0];

						post._parent = parent;

						img.className = "troll";
						parent.insertBefore(img, parent.firstChild.nextSibling);

						parent.setAttribute("troll", troll);

						names[i].innerHTML = names[i].innerHTML.replace("Tubasing", "Tubashit");

						if (typeof(comments[name]) == "undefined")
							comments[name] = [];

						comments[name].push({
							parent: parent,
							post: post
						});

						img.addEventListener("click", function(e)
						{
							let troll = toggleTroll(post);
							if (troll)
								trollAdd(name);
							else
								trollRemove(name);

							for(let i = 0; i < comments[name].length; i++)
							{
								if (post === comments[name][i].post)
									continue;

								toggleTroll(comments[name][i].post);
							}
						}, false);



						let timer,
								prev,
								eventHandler = function(e)
								{
									if (parent.getAttribute("troll") != "true")
										return;

									let type = e.type == "mouseenter";

									if (prev == e.type)
										return;

									prev = e.type;
									clearTimeout(timer);
									timer = setTimeout(function()
									{
										censorText(post, type);
									}, type ? 100 : 1000);
								};
						body.addEventListener("mouseenter", eventHandler, false);
						body.addEventListener("mouseleave", eventHandler, false);

						if (!troll)
							continue;

						censorText(post);
					}
				}, 100);
			}, 100);
		}, false);
	}
}//disqus
if (document.readyState != "loading")
	func();
else
	document.addEventListener("DOMContentLoaded", func ,true);