Horriblesubs Release Time Until

Change times on horriblesubs to "until/ago", highlight shows you're watching, and highlights newly added shows, and adds links to various anime databases

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Horriblesubs Release Time Until
// @namespace    horriblesubs_release_time_until
// @description  Change times on horriblesubs to "until/ago", highlight shows you're watching, and highlights newly added shows, and adds links to various anime databases
// @homepageURL  https://github.com/namiman/horriblesubs_release_time_until
// @author       namiman
// @version      1.4.3
// @date         2018-01-11
// @include      /^https?:\/\/horriblesubs\.info\/.*/
// @require      https://code.jquery.com/jquery-3.2.1.slim.min.js
// @grant        none
// ==/UserScript==

console.log( "Horriblesubs Release Time Until userscript loaded" );

var key = {
	user_shows: 'hrtu_user_shows',
	all_shows: 'hrtu_all_shows',
	version: 'hrtu_last_version',
	state: 'hrtu_release_schedule_state',
};
var is_new_install = false;
var current_version = '1.4.3';
var user_shows = JSON.parse( localStorage.getItem( key.user_shows ) );
if ( ! user_shows )
	user_shows = {};
var all_shows = JSON.parse( localStorage.getItem( key.all_shows ) );
if ( ! all_shows )
	all_shows = {};
var script_version = localStorage.getItem( key.version );
if ( ! script_version ) {
	is_new_install = true;
	script_version = current_version;
}
var state = JSON.parse( localStorage.getItem( key.state ) );
if ( ! state ) {
	state = {
		saved: 1,
		unsaved: 1,
		new: 1,
	};
}

function updateVersion() {
	if ( is_new_install ) {
		console.log( "HRTU version: "+ current_version );
		showAlert( 'Congratulations on installing <a href="https://github.com/namiman/horriblesubs_release_time_until/">HRTU</a>. You may find instructions on the <a href="/release-schedule/">release schedule</a> page. <div class="close">x</div>' );
	}
	localStorage.setItem( key.version, current_version );
}

var weekdays = [
	"YABOI", // horriblesubs starts the week on monday, not sunday
	"Monday",
	"Tuesday",
	"Wednesday",
	"Thursday",
	"Friday",
	"Saturday",
	"Sunday"
];

function parseTime( str ) {
	var match = str.match( /(\d+):(\d+)/ );
	return {
		hours: match[1],
		minutes: match[2]
	};
}
function timeAgo( hours, minutes, day ) {
	var now = new Date();
	var dst_start = new Date( now.getFullYear(), 3, 8 );
	var dst_end = new Date( now.getFullYear(), 11, 1 );
	var offset = ( now > dst_start && now < dst_end ) ? -7 : -8 ;
	var pacific_time = new Date( now.getTime() + ( offset * 3600 * 1000 ) );

	var time_show = new Date( pacific_time.getFullYear(), pacific_time.getMonth(), pacific_time.getDate(), 0, 0, 0 );
	var pacific_day = pacific_time.getDay();
	// if it is sunday(pacific), then the actual day will be 0, but horriblesubs day will be 7, so set it to 0, but only on sundays
	var day_diff = ( day == 7 && pacific_day === 0 ) ? 0 : ( day - pacific_day );
		time_show.setDate( pacific_time.getDate() + day_diff );
		time_show.setHours( parseInt( hours ) + parseInt( offset ) );
		time_show.setMinutes( minutes );

	var time_units;
	var time_until = Math.round( ( time_show - pacific_time ) / 1000 / 60 );
	var time_direction = (time_until > 0) ? 1 : (time_until === 0) ? 0 : -1;
	time_until = Math.abs( time_until );
	if ( time_until === 0 )
		time_units = '';
	else if ( time_until > 60 ) {
		time_until = ( time_until / 60 ).toFixed( 1 );
		time_units = ( time_until > 1 ) ? 'hrs' : 'hr';
	}
	else
		time_units = ( time_until > 1 ) ? 'mins' : 'min';

	var ending_phrase = (time_direction > 0) ? 'until' : (time_direction === 0) ? 'now' : 'ago';

	return {
		'text': ( time_direction === 0 ) ? ending_phrase : time_until + ' ' + time_units + ' ' + ending_phrase,
		'time': time_until,
		'direction': time_direction
	};
}

function linkIdentifier( link ) {
	return link.substr( link.lastIndexOf( '/' ) + 1 );
}

function sideBar() {
	if ( ! jQuery( ".schedule-today:not( .hrtu_sidebar )" ).length ) {
		console.warn( "Horriblesubs Release Time Until sideBar(): Unable to find '.schedule-today'" );
		return false;
	}
	
	jQuery( ".schedule-today:not( .hrtu_sidebar ) .schedule-table tr" ).each(function(){
		var row = jQuery(this);
		var title_el = row.find( ".schedule-widget-show" );
		var no_link = false;
		if ( ! title_el.length ) {
			title_el = row.find( ".schedule-show" );
			no_link = true;
		}
		if ( ! title_el.hasClass( "hrtu_sidebar_show_name" ) ) {
			title_el.addClass( "hrtu_sidebar_show_name" );
		}
		var title, link;
		if ( no_link ) {
			title = fixTitle( title_el.text() );
			title_el.text( title );
		}
		else {
			title = fixTitle( title_el.find( "a" ).text() );
			link = linkIdentifier( title_el.find( "a" ).attr( "href" ) );
			title_el.find( "a" ).text( title );
		}

		if ( isUserShow( title, link ) )
			row.addClass( "hrtu_sidebar_highlight" );
		else
			row.removeClass( "hrtu_sidebar_highlight" );

		if ( ! isAllShow( title, link ) )
			row.addClass( "hrtu_sidebar_highlight_new" );
		else
			row.removeClass( "hrtu_sidebar_highlight_new" );
		
		var time_el = row.find( '.schedule-time' );
		var time_text;
		if ( time_el[0].hasAttribute( 'data-hrtu-time' ) )
			time_text = time_el.attr( 'title' );
		else
			time_text = time_el.text();
		var match = parseTime( time_text );
		var today = new Date();
		var show = timeAgo( match.hours, match.minutes, today.getDay() );
		time_el
			.attr( 'title', time_text )
			.attr( 'data-hrtu-time', show.time )
			.text( show.text )
			.addClass( 'hrtu_time' );
		if ( show.direction < 0 )
			time_el.addClass( 'hrtu_release_page_time_passed' );
	});

	jQuery( ".schedule-today:not( .hrtu_sidebar ) .schedule-table" ).unbind( "click.hrtu_sidebar_show_name" ).on( "click.hrtu_sidebar_show_name", ".hrtu_sidebar_highlight_new .hrtu_sidebar_show_name", function( event ){
		var el = jQuery(this)[0];
		if ( event.offsetX < el.offsetWidth ) {
			var anchor_el = jQuery( el ).find( "a" ).first();
			var title, link;
			if ( ! anchor_el.length ) {
				var show_el = jQuery( el ).find( ".schedule-show" );
				title = fixTitle( show_el.text() );
			}
			else {
				title = fixTitle( anchor_el.text() );
				link = linkIdentifier( anchor_el.attr( "href" ) );
			}
			addShow( title, link );
			releasePage();
			sideBar();
		}
	});
}

/*
	Fixes bug where titles had differing types of dashes,
	in different places on the website, and as a result
	would not match against each other.
*/
function fixTitle( str ) {
	return str.replace( /\u2013|\u002D/g, "-" );
}

function addShow( title, link ) {
	if ( typeof all_shows[ title ] !== "undefined" ) {
		if ( link ) {
			all_shows[ link ] = 1;
			delete all_shows[ title ];
		}
		else {
			all_shows[ title ] = 1;
		}
	}
	else {
		if ( link )
			all_shows[ link ] = 1;
		else
			all_shows[ title ] = 1;
	}
	localStorage.setItem( key.all_shows, JSON.stringify( all_shows ) );
}

function isAllShow( title, link ) {
	if ( ( typeof all_shows[ title ] !== "undefined" ) ) {
		if ( link ) {
			all_shows[ link ] = JSON.parse( JSON.stringify( all_shows[ title ] ) );
			delete all_shows[ title ];
		}
		else {
			all_shows[ title ] = 1;
		}
		localStorage.setItem( key.all_shows, JSON.stringify( all_shows ) );
		return true;
	}
	else {
		return ( typeof all_shows[ link ] !== "undefined" );
	}
}

function addUserShow( title, link ) {
	if ( typeof user_shows[ title ] !== "undefined" ) {
		if ( link ) {
			user_shows[ link ] = 1;
			delete user_shows[ title ];
		}
		else {
			user_shows[ title ] = 1;
		}
	}
	else {
		if ( link )
			user_shows[ link ] = 1;
		else
			user_shows[ title ] = 1;
	}
	localStorage.setItem( key.user_shows, JSON.stringify( user_shows ) );

	if ( ! isAllShow( title, link ) )
		addShow( title, link );
}

function removeUserShow( title, link ) {
	delete user_shows[ title ];
	delete user_shows[ link ];
	localStorage.setItem( key.user_shows, JSON.stringify( user_shows ) );
}
function isUserShow( title, link ) {
	if ( ( typeof user_shows[ title ] !== "undefined" ) ) {
		if ( link ) {
			user_shows[ link ] = JSON.parse( JSON.stringify( user_shows[ title ] ) );
			delete user_shows[ title ];
		}
		else {
			user_shows[ title ] = 1;
		}
		localStorage.setItem( key.user_shows, JSON.stringify( user_shows ) );
		return true;
	}
	else {
		return ( typeof user_shows[ link ] !== "undefined" );
	}
}

function releasePageUserRefreshShowView( el, title, link, is_user_saved, is_all_saved ) {
	is_all_saved = is_all_saved || isAllShow( title, link );

	if ( is_user_saved )
		el.parent().addClass( "hrtu_release_page_highlight" );
	else
		el.parent().removeClass( "hrtu_release_page_highlight" );

	if ( is_all_saved )
		el.parent().removeClass( "hrtu_release_page_highlight_new" );
	else
		el.parent().addClass( "hrtu_release_page_highlight_new" );

}

function releasePageMakeShow( title_el, has_link ) {

	var anchor_el,
		link,
		title;

	if ( has_link ) {
		anchor_el = title_el.find( "a" ).first();
		link = linkIdentifier( anchor_el.attr( "href" ) );
		title = fixTitle( anchor_el.text() );
		anchor_el.text( title );
	}
	else {
		title = fixTitle( title_el.text() );
		title_el.text( title );
	}

	/* set up user shows */
	if ( isUserShow( title, link ) )
		title_el.parent().addClass( "hrtu_release_page_highlight" );
	else
		title_el.parent().removeClass( "hrtu_release_page_highlight" );

	if ( ! title_el.find( '.hrtu_release_page_toggle' ).length ) {

		title_el.append( '<div class="hrtu_release_page_toggle"></div>' );

		title_el.unbind( "click.hrtu_release_page_toggle" ).on( "click.hrtu_release_page_toggle", ".hrtu_release_page_toggle", function(e){
			var el = jQuery(this),
				title,
				link;

			var has_link = el.parent().hasClass( "schedule-page-show" );

			if ( has_link ) {
				title = el.parent().find( "a" ).text();
				link = linkIdentifier( el.parent().find( "a" ).attr( "href" ) );
			}
			else
				title = el.parent().text();

			var is_saved = el.parent().parent().hasClass( "hrtu_release_page_highlight" );
			if ( is_saved ) {
				removeUserShow( title, link );
				hrtuSidebarRemoveShow( title );
				releasePageUserRefreshShowView( el.parent(), title, link, false );
			}
			else {
				addUserShow( title, link );
				releasePageUserRefreshShowView( el.parent(), title, link, true );
			}

			sideBar();
			e.stopPropagation();
		});
	}

	/* set up new show */
	if ( ! isAllShow( title, link ) ) {
		title_el.parent().addClass( "hrtu_release_page_highlight_new" );

		if ( ! title_el.find( '.hrtu_release_page_toggle_new' ).length ) {

			title_el.append( '<div class="hrtu_release_page_toggle_new"></div>' );

			title_el.unbind( "click.hrtu_release_page_toggle_new" ).on( "click.hrtu_release_page_toggle_new", ".hrtu_release_page_toggle_new", function(e){

				var title,
					link,
					el = jQuery(this);

				var has_link = el.parent().hasClass( "schedule-page-show" );

				if ( has_link ) {
					title = el.parent().find( "a" ).text();
					link = linkIdentifier( el.parent().find( "a" ).attr( "href" ) );
				}
				else {
					title = el.parent().text();
				}

				addShow( title, link );	
				releasePageUserRefreshShowView( el.parent(), title, link, isUserShow( title, link ) );			
				sideBar();
				e.stopPropagation();
			});
		}
	}
	else
		title_el.parent().removeClass( "hrtu_release_page_highlight_new" );
}

function updateStateClass( property ) {

	var result = state[ property ];

	if ( property == "new" )
		var el = jQuery( "#hrtu_view_new" );
	else if ( property == "saved" )
		var el = jQuery( "#hrtu_view_saved" );
	else if ( property == "unsaved" )
		var el = jQuery( "#hrtu_view_unsaved" );
	else
		return false;
	
	if ( result )
		el.addClass( "selected" );
	else
		el.removeClass( "selected" );
}

function updateStateView( property ) {

	var result = state[ property ];

	if ( property == "new" )
		var el = jQuery( ".schedule-page-item.hrtu_release_page_highlight_new" );
	else if ( property == "saved" )
		var el = jQuery( ".schedule-page-item.hrtu_release_page_highlight" );
	else if ( property == "unsaved" )
		var el = jQuery( ".schedule-page-item:not( .hrtu_release_page_highlight ):not( .hrtu_release_page_highlight_new )" );
	else
		return false;

	if ( result )
		el.show();
	else
		el.hide();

}

function getState( property ) {
	return state[ property ];
}

function updateState( property, value ) {

	if ( typeof value !== "undefined" )
		state[ property ] = value;

	updateStateClass( property );
	updateStateView( property );
	saveStateData();

}

function saveStateData() {
	localStorage.setItem( key.state, JSON.stringify( state ) );
}

function updateAllStateViews() {

	var properties = [
		"new",
		"saved",
		"unsaved",
	];

	properties.forEach(function( property ){
		updateState( property );
	});
}

function releasePage() {

	if ( ! jQuery( '.entry-content' ).length || ! jQuery( '.entry-content' ).children().length ) {
		console.warn( "Horriblesubs Release Time Until releasePage(): Unable to find release entries" );
		return false;
	}

	if ( ! jQuery( '.hrtu_instructions' ).length ) {
		jQuery( jQuery( ".entry-content ul" ).get(0) ).append(
			'<li class="hrtu_instructions">Click [+] or [-] on shows you\'re watching to highlight them</li>' +
			'<li class="hrtu_instructions">Shows with [NEW] are newly listed, click on [NEW] to unmark individual shows or <span id="hrtu_unmark_all_new" class="hrtu_button">click&nbsp;here</span> to unmark all of them at once.</li>' +
			'	<li class="hrtu_instructions">Currently viewing: <span id="hrtu_view_new" class="hrtu_button option">New</span> - <span id="hrtu_view_saved" class="hrtu_button option">Saved</span> - <span id="hrtu_view_unsaved" class="hrtu_button option">Unsaved</span></li>'
		);
	}

	jQuery( '#hrtu_unmark_all_new' ).unbind( "click" ).on( "click", function(){
		jQuery( '.schedule-page-show' ).each(function(){
			var anchor_el = jQuery(this).find( "a" ).first();
			var title = fixTitle( anchor_el.text() );
			var link = linkIdentifier( anchor_el.attr( "href" ) );
			addShow( title, link );
			releasePage();
			sideBar();
		});
	});

	// toggle saved items
	jQuery( "#hrtu_view_new" ).unbind( "click" ).on( "click", function(){
		if ( getState( "new" ) )
			updateState( "new", 0 );
		else
			updateState( "new", 1 );
	});

	// toggle unsaved items
	jQuery( "#hrtu_view_saved" ).unbind( "click" ).on( "click", function(){
		if ( getState( "saved" ) )
			updateState( "saved", 0 );
		else
			updateState( "saved", 1 );
	});

	// toggle new items
	jQuery( "#hrtu_view_unsaved" ).unbind( "click" ).on( "click", function(){
		if ( getState( "unsaved" ) )
			updateState( "unsaved", 0 );
		else
			updateState( "unsaved", 1 );
	});

	var entry_day;
	jQuery( '.entry-content' ).children().each(function(){
		var el = jQuery(this);
		if ( el.hasClass( 'weekday' ) ) {
			if ( el.text() == "To be scheduled" )
				entry_day = 'tbd';
			else
				entry_day = weekdays.indexOf( el.text() );
		}
		else if ( el.hasClass( 'schedule-today-table' ) ) {

			el.find( '.schedule-page-show' ).each(function(){
				releasePageMakeShow( jQuery(this), true );
			});

			el.find( '.schedule-show' ).each(function(){
				releasePageMakeShow( jQuery(this), false );
			});

			el.find( '.schedule-time' ).each(function(){
				var show;
				var time_el = jQuery(this);
				if ( ! time_el.length ) {
					console.warn( "Horriblesubs Release Time Until releasePage(): No .schedule-time found" );
					return false;
				}
				var time_text;
				if ( entry_day == 'tbd' || time_el.attr( 'title' ) === "" ) {
					show = {
						time: "00:00",
						text: "",
						direction: 1
					};
				}
				else {
					if ( time_el[0].hasAttribute( 'data-hrtu-time' ) )
						time_text = time_el.attr( 'title' );
					else
						time_text = time_el.text();
					
					time_el.title = time_text;
					var match = parseTime( time_text );
					if ( ! match )
						console.warn( "Horriblesubs Release Time Until releasePage(): Unable to parse release time ["+ time_text +"]" );
					show = timeAgo( match.hours, match.minutes, entry_day );
				}
				time_el
					.attr( 'title', time_text )
					.attr( 'data-hrtu-time', show.time )
					.text( show.text )
					.addClass( 'hrtu_time' )
					.parent()
						.addClass( 'hrtu_series_name' )
						.find( '.schedule-page-show' )
							.addClass( 'hrtu_series_name_text' );
				time_el
					.parent()
						.find( '.schedule-show' )
							.addClass( 'hrtu_series_name_text' );
				if ( show.direction < 0 )
					time_el.addClass( 'hrtu_release_page_time_passed' );

				if ( time_el.parent().hasClass( "hrtu_release_page_highlight" ) ) {
					var text_el = time_el.parent().find( ".schedule-page-show a" );
					var href;
					if ( ! text_el.length ) {
						text_el = time_el.parent().find( ".schedule-show" );
						href = "";
					}
					else {
						href = time_el.attr( 'href' );
					}

					hrtuSidebarAddShow( text_el.text(), show.time, show.text, href );
				}
			});
		}
	});

	updateAllStateViews();
}

function hrtuSidebarAddShow( title, otime, time_text, href ) {
	if ( ! jQuery( '#hrtu_sidebar' ).length ) {
		jQuery( '#sidebar .xoxo' ).first().append(
			'<li id="hrtu_sidebar" class="widget-container widget_text">' +
			'	<h3 class="widget-title">My Shows</h3>' +
			'	<div class="textwidget">' +
			'		<div class="schedule-today hrtu_sidebar">' +
			'			<table class="schedule-table" border="0" cellpadding="0" cellspacing="0">' +
			'				<tbody></tbody>' +
			'			</table>' +
			'		</div>' +
			'	</div>' +
			'</li>'
		);
	}

	var exists = false;
	jQuery( '#hrtu_sidebar .textwidget .schedule-table tbody td.hrtu_sidebar_show_name' ).each(function(){
		if ( jQuery(this).find( 'a' ).text() == title ) {
			exists = true;
			return false;
		}
	});
	if ( exists === false ) {
		var title_text = 'See all releases for this show';
		if ( ! href ) {
			href = '';
			title_text = '';
		}
		var color_class = ( /ago/.test( time_text ) ) ? "hrtu_release_page_time_passed" : "" ;
		jQuery( '#hrtu_sidebar .textwidget .schedule-table tbody' ).append(
			'<tr class="hrtu_sidebar_highlight">' +
			'	<td class="schedule-widget-show hrtu_sidebar_show_name">' +
			'		<a title="'+ title_text +'" href="'+ href +'">'+ title +'</a>' +
			'	</td>' +
			'	<td title="'+ otime +'" class="schedule-time hrtu_time '+ color_class +'">'+ time_text +'</td>' +
			'</tr>'
		);
	}
}

function hrtuSidebarRemoveShow( title ) {
	jQuery( '#hrtu_sidebar .textwidget .schedule-table tbody td.hrtu_sidebar_show_name' ).each(function(){
		if ( jQuery(this).find( 'a' ).text() == title ) {
			jQuery( this ).parent().remove();
			return false;
		}
	});
}

function addStyles() {
	jQuery( 'body' ).addClass( "hrtu" );
	jQuery( 'head' ).append(
		'<style type="text/css">' +
		'	.hrtu .hrtu_series_name {' +
		'		padding: 0px 6px;' +
		'	}' +
		'	.hrtu .hrtu_series_name:hover {' +
		'		background-color: rgb( 230,230,230 );' +
		'	}' +
		'	.hrtu .hrtu_series_name_text {' +
		'		position: relative;' +
		'		overflow: visible;' +
		'		white-space: normal;' +
		'	}' +
		'	.hrtu .hrtu_sidebar_show_name {' +
		'		width: 60%;' +
		'		position: relative;' +
		'		overflow: visible;' +
		'		white-space: normal;' +
		'	}' +
		'	.hrtu .hrtu_sidebar_highlight {' +
		'		color: rgb( 0,0,0 );' +
		'		font-weight: bold;' +
		'	}' +
		'	.hrtu .hrtu_sidebar_highlight .hrtu_sidebar_show_name:before, .hrtu .hrtu_sidebar_highlight_new .hrtu_sidebar_show_name:after {' +
		'		content: "";' +
		'		position: absolute;' +
		'		top: 6px;' +
		'		left: -10px;' +
		'		width: 6px;' +
		'		height: 6px;' +
		'		border-radius: 15px;' +
		'		background: rgb( 76,113,168 );' +
		'	}' +
		'	.hrtu .hrtu_sidebar_highlight_new .hrtu_sidebar_show_name:after {' +
		'		background: rgb( 220,0,0 );' +
		'	}' +
		'	.hrtu .hrtu_sidebar_highlight_new {' +
		'		color: rgb( 0,0,0 );' +
		'	}' +
		'	.hrtu .hrtu_release_page_time_passed {' +
		'		color: rgb( 179,179,179 );' +
		'	}' +
		'	.hrtu .hrtu_sidebar_highlight .hrtu_release_page_time_passed {' +
		'		color: rgb( 129,129,129 );' +
		'	}' +
		'	.hrtu .hrtu_sidebar_highlight_new .hrtu_sidebar_show_name:before {' +
		'		content: "[NEW]";' +
		'		font-size: 12px;' +
		'		font-weight: bold;' +
		'		font-family: sans-serif;' +
		'		color: rgb( 220,0,0 );' +
		'		margin-right: 5px;' +
		'		cursor: pointer;' +
		'	}' +
		'	.hrtu .hrtu_release_page_highlight {' +
		'		font-weight: bold;' +
		'	}' +
		'	.hrtu .hrtu_release_page_highlight .hrtu_series_name_text {' +
		'		position: relative;' +
		'	}' +
		'	.hrtu .hrtu_release_page_highlight .hrtu_series_name_text:before {' +
		'		content: "";' +
		'		position: absolute;' +
		'		top: 9px;' +
		'		left: -14px;' +
		'		width: 9px;' +
		'		height: 9px;' +
		'		border-radius: 15px;' +
		'		background: rgb( 98,151,176 );' +
		'	}' +
		'	.hrtu .hrtu_release_page_highlight .hrtu_release_page_time_passed {' +
		'		color: rgb( 144,144,144 );' +
		'	}' +
		'	.hrtu .hrtu_time {' +
		'		white-space: nowrap;' +
		'	}' +
		'	.hrtu .hrtu_release_page_toggle {' +
		'		width: 24px;' +
		'		height: 24px;' +
		'		text-align: center;' +
		'		line-height: 24px;' +
		'		cursor: pointer;' +
		'		display: inline-block;' +
		'		margin-left: 7px;' +
		'	}' +
		'	.hrtu .hrtu_release_page_toggle_new {' +
		'		display: none;' +
		'		text-align: center;' +
		'		line-height: 24px;' +
		'		cursor: pointer;' +
		'		display: inline-block;' +
		'		margin-left: 7px;' +
		'		color: rgb( 220,0,0 );' +
		'	}' +
		'	.hrtu .hrtu_release_page_highlight_new .hrtu_release_page_toggle_new {' +
		'		display: inline-block' +
		'	}' +
		'	.hrtu .hrtu_release_page_toggle:before {' +
		'		content: "[+]";' +
		'	}' +
		'	.hrtu .hrtu_release_page_highlight .hrtu_release_page_toggle:before {' +
		'		content: "[-]";' +
		'	}' +
		'	.hrtu .hrtu_release_page_highlight_new .hrtu_release_page_toggle_new:before {' +
		'		content: "[NEW]";' +
		'		font-weight: bold;' +
		'	}' +
		'	.hrtu .hrtu_release_page_highlight_new .hrtu_series_name_text:after {' +
		'		content: "";' +
		'		position: absolute;' +
		'		top: 9px;' +
		'		left: -14px;' +
		'		width: 9px;' +
		'		height: 9px;' +
		'		border-radius: 15px;' +
		'		background: rgb( 220,0,0 );' +
		'	}' +
		'	.hrtu_button {' +
		'		height: 22px;' +
		'		border: 1px solid rgb( 200,200,200 );' +
		'		cursor: pointer;' +
		'		color: rgb( 0,102,204 );' +
		'		border-radius: 25px;' +
		'		padding: 0px 8px 2px;' +
		'		box-shadow: 0px 0px 5px rgba( 0,0,0, 0.1 );' +
		'	}' +
		'	.hrtu_button:hover {' +
		'		border-color: rgb( 120,120,120 );' +
		'	}' +
		'	.hrtu_button.option:before {' +
		'		content: "✖";' +
		'		color: red;' +
		'		padding-right: 3px;' +
		'	}' +
		'	.hrtu_button.option.selected:before {' +
		'		content: "✓";' +
		'		color: green;' +
		'	}' +
		'	.hrtu_show_outbound_links {' +
		'		padding: 0px 8px 2px;' +
		'		display: inline-block;' +
		'		margin-top: 14px;' +
		'		floaT: right;' +
		'	}' +
		'	.hrtu_show_outbound_link {' +
		'		display: inline-block;' +
		'		color: rgb( 170,175,191 );' +
		'		border-right: 1px solid rgb( 220,220,220 );' +
		'		font-style: italic;' +
		'		padding: 0px 7px 0px 3px;' +
		'	}' +
		'	.hrtu_show_outbound_link:last-child {' +
		'		border: 0px;' +
		'	}' +
		'	#hrtu_alert {' +
		'		position: fixed;' +
		'		top: 0px;' +
		'		left: 0px;' +
		'		background: rgb( 255,0,0 );' +
		'		padding: 10px;' +
		'		color: rgb( 255,255,255 );' +
		'		width: calc( 100% - 20px );' +
		'		text-align: center;' +
		'		font-size: 15px;' +
		'	}' +
		'	#hrtu_alert a {' +
		'		color: rgb( 255,255,255 );' +
		'	}' +
		'	#hrtu_alert .close {' +
		'		float: right;' +
		'		border: 1px solid rgb( 255,255,255 );' +
		'		border-radius: 10px;' +
		'		padding: 0px 6px 4px;' +
		'		line-height: 14px;' +
		'		cursor: pointer' +
		'	}' +
		'	.hrtu_sidebar  .hrtu_sidebar_highlight .hrtu_sidebar_show_name:before {' +
		'		display: none;' +
		'	}' +
		'	.ind-show, .ind-show a {' +
		'		white-space: unset;' +
		'	}' +
		'</style>'
	);
}

function allShowsPage() {
	if ( ! jQuery( ".entry-content" ).hasClass( "hrtu_instruction" ) ) {

		jQuery( ".entry-content" )
			.addClass( "hrtu_instruction" )
			.prepend(
				'<ul>' +
				'	<li class="hrtu_instructions">Click [+] or [-] on shows you\'re watching to highlight them</li>' +
				'	<li class="hrtu_instructions">Shows with [NEW] are newly listed, click on [NEW] to unmark individual shows or <span id="hrtu_unmark_all_new" class="hrtu_button">click&nbsp;here</span> to unmark all of them at once.</li>' +
				'	<li class="hrtu_instructions">Currently viewing: <span id="hrtu_view_new" class="hrtu_button option selected">New</span> - <span id="hrtu_view_saved" class="hrtu_button option selected">Saved</span> - <span id="hrtu_view_unsaved" class="hrtu_button option selected">Unsaved</span></li>' +
				'</ul>'
			);

		jQuery( "#hrtu_unmark_all_new" ).unbind( "click" ).on( "click", function(){
			jQuery( ".ind-show" ).each(function(){
				var title_el = jQuery(this);
				var anchor_el = title_el.find( "a" ).first();
				var title = ( title_el.hasClass( "linkful" ) ) ? fixTitle( anchor_el.text() ) : fixTitle( title_el.text() );
				var link = ( title_el.hasClass( "linkful" ) ) ? linkIdentifier( anchor_el.attr( "href" ) ) : null;
				addShow( title, link );
				title_el.removeClass( "hrtu_release_page_highlight_new" );
				sideBar();
			});
		});

		// toggle saved items
		jQuery( "#hrtu_view_saved" ).unbind( "click" ).on( "click", function(){
			var el = jQuery(this);
			el.toggleClass( "selected" );
			if ( el.hasClass( "selected" ) )
				jQuery( ".ind-show.hrtu_release_page_highlight" ).show();
			else
				jQuery( ".ind-show.hrtu_release_page_highlight" ).hide();
		});

		// toggle unsaved items
		jQuery( "#hrtu_view_unsaved" ).unbind( "click" ).on( "click", function(){
			var el = jQuery(this);
			el.toggleClass( "selected" );
			if ( el.hasClass( "selected" ) )
				jQuery( ".ind-show:not( .hrtu_release_page_highlight ):not( .hrtu_release_page_highlight_new )" ).show();
			else
				jQuery( ".ind-show:not( .hrtu_release_page_highlight ):not( .hrtu_release_page_highlight_new )" ).hide();
		});

		// toggle new items
		jQuery( "#hrtu_view_new" ).unbind( "click" ).on( "click", function(){
			var el = jQuery(this);
			el.toggleClass( "selected" );
			if ( el.hasClass( "selected" ) )
				jQuery( ".ind-show.hrtu_release_page_highlight_new" ).show();
			else
				jQuery( ".ind-show.hrtu_release_page_highlight_new" ).hide();
		});

	}

	jQuery( ".ind-show" ).each(function(){
		var title_el = jQuery(this);
		var anchor_el = title_el.find( "a" ).first();
		var title = ( title_el.hasClass( "linkful" ) ) ? fixTitle( anchor_el.text() ) : fixTitle( title_el.text() );
		var link = ( title_el.hasClass( "linkful" ) ) ? linkIdentifier( anchor_el.attr( "href" ) ) : null;
		//var title = fixTitle( anchor_el.text() );
		//var link = linkIdentifier( anchor_el.attr( "href" ) );
		anchor_el.text( title );

		if ( title_el.hasClass( "linkless" ) )
			anchor_el = title_el;

		if ( isUserShow( title, link ) )
			title_el.addClass( "hrtu_release_page_highlight" );
		else
			title_el.removeClass( "hrtu_release_page_highlight" );

		if ( ! anchor_el.find( '.hrtu_release_page_toggle' ).length ) {
			anchor_el.append( '<div class="hrtu_release_page_toggle"></div>' );
			anchor_el.unbind( "click.hrtu_release_page_toggle" ).on( "click.hrtu_release_page_toggle", ".hrtu_release_page_toggle", function(e){
				e.stopImmediatePropagation();
				e.preventDefault();
				// parent code here isn't working for .linkless items
				var parent_el = ( jQuery(this).parent().hasClass( "linkless" ) ) ? jQuery(this).parent() : jQuery(this).parent().parent();
				var is_saved = parent_el.hasClass( "hrtu_release_page_highlight" );
				if ( is_saved ) {
					removeUserShow( title, link );
					hrtuSidebarRemoveShow( title );
					parent_el.removeClass( "hrtu_release_page_highlight" );
				}
				else {
					addUserShow( title, link );
					parent_el.addClass( "hrtu_release_page_highlight" ).removeClass( "hrtu_release_page_highlight_new" );
				}
				sideBar();
			});
		}

		/* set up new show */
		if ( ! isAllShow( title, link ) ) {
			title_el.addClass( "hrtu_release_page_highlight_new" );
			if ( ! anchor_el.find( '.hrtu_release_page_toggle_new' ).length ) {
				anchor_el.append( '<div class="hrtu_release_page_toggle_new"></div>' );
				anchor_el.unbind( "click.hrtu_release_page_toggle_new" ).on( "click.hrtu_release_page_toggle_new", ".hrtu_release_page_toggle_new", function(e){
					e.stopImmediatePropagation();
					e.preventDefault();
					addShow( title, link );
					jQuery(this).parent().parent().removeClass( "hrtu_release_page_highlight_new" );
					sideBar();
				});
			}
		}
		else
			title_el.removeClass( "hrtu_release_page_highlight_new" );
	});
	
}

function showPage() {

	jQuery( "article" ).each(function(){
		var el = jQuery(this);
		var title = encodeURIComponent( el.find( "> header .entry-title" ).text() );
		var info_el = el.find( ".series-info" );
		if ( ! info_el.find( ".hrtu_show_outbound_links" ).length ) {
			info_el.append(
				'<div class="hrtu_show_outbound_links">' +
				'	<a class="hrtu_show_outbound_link" href="https://anidb.net/perl-bin/animedb.pl?adb.search='+ title +'&show=animelist&do.search=search">aniDB</a>' +
				'	<a class="hrtu_show_outbound_link" href="https://www.anime-planet.com/anime/all?name='+ title +'">Anime-Planet</a>' +
				'	<a class="hrtu_show_outbound_link" href="https://myanimelist.net/anime.php?q='+ title +'">MAL</a>' +
				'	<a class="hrtu_show_outbound_link" href="https://hummingbird.me/search?query='+ title +'">Hummingbird</a>' +
				'</div>'
			);
		}
	});
	
}

function splashPage() {

	waitForElement( ".episodecontainer .latest .release-info", function( element ){

		element.each(function(){
			var el = jQuery(this).find( "tr" );
			var link_el = el.find( "td.rls-label a" );
			if ( ! link_el.length )
				return true;
			var link = linkIdentifier( link_el.attr( "href" ) );
			if ( isUserShow( null, link ) )
				el.addClass( "hrtu_release_page_highlight" );
		});

	});

}

function showAlert( message ) {

	jQuery( "body" ).append( '<div id="hrtu_alert">'+ message +'</div>' );
	jQuery( "#hrtu_alert .close" ).unbind( "click" ).on( "click", function(){
		jQuery(this).parent().slideUp();
	});
	
}

function waitForElement( identifier, callback ) {
	var give_up = 400;
	var interval = setInterval(function(){
		var el = jQuery( identifier );
		if ( el.length ) {
			clearInterval( interval );
			callback( el );
		}
		else if ( --give_up < 0 ) {
			clearInterval( interval );
			callback( false );
		}
	}, 300 );
}


/* Userscript Logic */

updateVersion();

addStyles();
sideBar();
if ( window.location.pathname == '/' )
	splashPage();
else if ( window.location.pathname == '/release-schedule/' )
	releasePage();
else if ( /\/shows\/./.test( window.location.pathname ) )
	showPage();
else if ( /\/(shows|current-season)\/?$/.test( window.location.pathname ) )
	allShowsPage();

setInterval( function(){
	sideBar();
	if ( window.location.pathname == '/release-schedule/' )
		releasePage();
}, 30000 );