Airdates.tv show past weeks

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

目前為 2017-06-25 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

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

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name        Airdates.tv show past weeks
// @namespace   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=
// @version     1.8
// @run-at document-start
// @ noframes
// @grant       none
// ==/UserScript==

//tab = 2 spaces

let log = console.log;
let func = function(e)
{
	let _today;

/*
fixing browser history inflating after each page refresh and prev/next history jump don't work
*/
var prevPath;
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");

	var 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();
	};

	if(ymCurrent != ym){
		$(".days").load("/_archive/" + ~~(ym/12) + "-" + ~~((ym%12)+1), function(){
			ymCurrent = ym;
			whenDone();
		});
	}
	else{
		whenDone();
	}
}

//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);
});
/*
end fixing browser history inflating after each page refresh and prev/next history jump don't work
*/

window.loadArchiveFromPathname = loadArchiveFromPathname;
function showPast()
{
// hide all past days
	var	d = new Date();

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

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

	let	firstDay = $(".days").children().first(),
			firstDate = firstDay.attr("data-date"),
			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();
	}
}//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(readCookieRaw("w")),
			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(var i = weeksMax; i > 0; i--)
			$( "div.calendar" ).toggleClass("showPast" + i, (weeks >= i));

		createCookie("w", 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
		var dropdown = document.createElement("select");
		dropdown.id = "pastWeeks";

		for(var i = 0; i <= weeksMax; i++)
		{
			var 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);

		var 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;
//adding attribute "opened" to the entry allows us show/hide things from CSS based on entry state
$("div.days").on("click", "div.entry div.title", function()
{
	if (prevOpened)
	{
		prevOpened.attr("opened", "");
		let po = prevOpened;
		setTimeout(function()
		{
			po.removeAttr("opened");
		}, 200);
		prevOpened = null;
	}

	let $entry = $( this ).parent();
	if ($entry.attr("opened") === undefined)
	{
		$entry.attr("opened", "");
//idealy this should've been done via "on complete" function submitted for slideUp/slideDown
		setTimeout(function()
		{
			$entry.attr("opened", "1");
		}, 300);
		prevOpened = $entry;
	}
});

//create stylesheet. A little trick to have multi-line text in javascript
var	style = document.createElement("style"),
		css = function(){/*
.past
{
	display: none;
}

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 > span
{
	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:hover
{
	background-color: #ffffd5;
}

div[white] div.title:hover
{
	color: black;
}

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

.entry[opened][white]
{
	border-color: grey;
}

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

*/};

style.innerHTML = css.toString().slice(14, -3).replace(/\*\/\/\*/g, "*/");
$("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 == '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();
});

let engines = window.engines;

//middle click on day's title opens selected engines for user's shows
let _engines = [],
		list = ["Piratebay"];
for(let i = 0; i < engines.length; i++)
{
	let n = list.indexOf(engines[i].name);
	if (n != -1)
	{
		_engines.push(engines[i]);
		//sort by date instead of seeds
		engines[i].href = engines[i].href.replace(/\/0\/7\/0$/, "/0/3/0");
	}
}

$("div.date").on("mousedown", function(e)
{
	if (e.button != 1)
		return;

	e.stopPropagation();
	e.preventDefault();
	let func = function()
	{
		let el = $(this),
				MONKEY_ID = encodeURIComponent( el.data("series-id") );
		if (!DB.getColor(MONKEY_ID))
			return;

		let title = el.children("div.title").text().replace("?", ""),
				MONKEY = encodeURIComponent( title ),
				MONKEY_N = encodeURIComponent( title.replace( /S[0-9]+E[0-9]+$/g, '' ) ),
				WIKI_TITLE = encodeURIComponent( el.data("series-source") );

		$.each( _engines, function( i, engine ){
			let href = engine.href
				.replace( "MONKEY_ID", MONKEY_ID )
				.replace( "MONKEY_N", MONKEY_N )
				.replace( "MONKEY", MONKEY )
				.replace( "{WIKI_TITLE}", WIKI_TITLE );
			window.open(href, MONKEY);
		} );
	};
	$(this).parent().find("div.entry").each(func);
});

//sanitizing engine links
$( "body").on("click", "div.entry div.title", function(e)
{
	let obj = this;
	setTimeout(function()
	{
		$(obj).parent().find(".engines").children().each(function(i, o)
		{
			if (o.href)
				o.href = o.href.replace("%3F", "");

		});
	});
});

}

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

//disqus troll filter
	if (window.location.href.indexOf("disqus.com") != -1)
	{
		function postBody(obj)
		{
			if (obj && obj.className && obj.className.indexOf("post-content") != -1)
				return obj;
			return postBody(obj.parentNode);
		}
		function censor(a, b, c, d, e)
		{
			var p = "blah",
					r = "",
					caps = true,
					t,
					i,
					isStr = isNaN(a.replace(/['`].*/, ''));

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

		function censorText(obj)
		{
			var c = obj.childNodes;
			for(var i = 0; i < c.length; i++)
			{
				if (c[i].nodeName == "#text")
					c[i].nodeValue = c[i].nodeValue.replace(/(\w+(['`]\w+)?)/g, censor);
				else if (c[i].childNodes.length)
					censorText(c[i]);
			}
			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);
					for(let i = 0; i < names.length; i++)
					{
						if (names[i].innerHTML.match("Tubasing"))
						{
							names[i].innerHTML = names[i].innerHTML.replace("Tubasing", "Tubashit");
							let body = postBody(names[i])
							body.className += " troll";
							let post = body.getElementsByClassName("post-body-inner")[0];
							post.origHTML = post.innerHTML;
							post.trollHTML = censorText(post);
							let timer,
									prev
							let eventHandler = function(e)
									{
										let type = e.type == "mouseenter";

										if (prev == e.type)
											return;

										prev = e.type;
										clearTimeout(timer);
										timer = setTimeout(function()
										{
											let innerHTML = type ? post.origHTML : post.trollHTML;
											if (post.innerHTML != innerHTML)
												post.innerHTML = innerHTML;
										}, type ? 100 : 1000);
									}
							body.addEventListener("mouseenter", eventHandler, false);
							body.addEventListener("mouseleave", eventHandler, false);
						}
					}
				}, 100);
			}, 100);
		}, false)
	}
}

document.addEventListener("DOMContentLoaded", func ,true);