_@/ tvguide

By crazysnailboy Last update Apr 2, 2010 — Installed 921 times.

There are 6 previous versions of this script.

// ==UserScript==
// @name           _@/ tvguide
// @author         Chris Porter
// @version        0.6d
// @date           2010-04-02
// @namespace      http://www.crazysnailboy.net/greasemonkey/
// @include        http://www.tvguide.co.uk/*
// ==/UserScript==

var GM_consoleLineOffset = 10 /* current line number */; try { generateError(); } catch(error){ GM_consoleLineOffset = (error.lineNumber - GM_consoleLineOffset); }
var GM_log = function(){ if (unsafeWindow.console == undefined){ return; } unsafeWindow.console.log(arguments[0]); };
var GM_logError = function() { if (unsafeWindow.console == undefined){ return; } unsafeWindow.console.error(((typeof(arguments[0].method) == "undefined") ? "" : arguments[0].method + ": ") + arguments[0].name + " - " + arguments[0].message + ", line " + (arguments[0].lineNumber-GM_consoleLineOffset)); };

document._createElement=document.createElement;document.createElement=function(tagName,attributes){var element=this._createElement(tagName);if(attributes!=undefined){for(var attribute in attributes){if(attributes.hasOwnProperty(attribute)){switch(attribute){case"innerHTML":element.innerHTML=attributes[attribute];break;default:element.setAttribute(attribute,attributes[attribute])}}}}return element};
document._evaluate=document.evaluate;document.evaluate=function(xpathExpression,contextNode,resultType){if(resultType==undefined){resultType=XPathResult.ANY_TYPE}if(contextNode==null){contextNode=this}var result=this._evaluate(xpathExpression,contextNode,null,resultType,null);switch(resultType){case XPathResult.NUMBER_TYPE:return result.numberValue;case XPathResult.STRING_TYPE:return result.stringValue;case XPathResult.BOOLEAN_TYPE:return result.booleanValue;case XPathResult.ANY_UNORDERED_NODE_TYPE:case XPathResult.FIRST_ORDERED_NODE_TYPE:return result.singleNodeValue;default:return result}return result};
document.getElementByXPath=function(xpathExpression,contextNode){var x=this.evaluate(xpathExpression,contextNode||this,XPathResult.FIRST_ORDERED_NODE_TYPE);return x};
document.getElementsByXPath=function(xpathExpression,contextNode){var x=this.evaluate(xpathExpression,contextNode||this,XPathResult.ORDERED_NODE_ITERATOR_TYPE);var result=[],next;while(next=x.iterateNext()){result.push(next)}return result};
document.removeElementsByXPath=function(xpathExpression,contextNode){var x=this.evaluate(xpathExpression,contextNode||this,XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE);for(var i=0;i<x.snapshotLength;i++){x.snapshotItem(i).parentNode.removeChild(x.snapshotItem(i))}return i};

if(!String.prototype.format){String.prototype.format=function(){var txt=this;for(var i=0;i<arguments.length;i++){var exp=new RegExp('\\{'+(i)+'\\}','gm');txt=txt.replace(exp,arguments[i])}return txt}}if(!String.format){String.format=function(){for(var i=1;i<arguments.length;i++){var exp=new RegExp('\\{'+(i-1)+'\\}','gm');arguments[0]=arguments[0].replace(exp,arguments[i])}return arguments[0]}}
if(!String.prototype.right){String.prototype.right=function(iLen){return this.substr(this.length-iLen,iLen)}}if(!String.right){String.right=function(sInput,iLen){return sInput.substr(sInput.length-iLen,iLen)}}



var isPostback = (location.pathname.indexOf("/gadget") == 0);
if (isPostback == false)
{

// =================================================================================================
// nowViewing
// =================================================================================================

	var nowViewing = {

		homePage: ((window.location.pathname == "/") || (window.location.pathname == "/default.asp")),

		viewAs: {
			get grid() { return (document.getElementsByXPath("//td[@class='title']/font[@color='black' and contains(text(),'GRID')]").length == 1); },
			get list() { return (document.getElementsByXPath("//td[@class='title']/font[@color='black' and contains(text(),'LIST')]").length == 1); }
		}

	};


// =================================================================================================
// eventListeners
// =================================================================================================

	var eventListeners = {

		toggleHighlightDisplayLinkClick: function(event)
		{
			try
			{
				var bShowHighlights = (event.target.innerHTML == "Show Highlight Pane");
				event.target.innerHTML = (bShowHighlights ? "Hide Highlight Pane" : "Show Highlight Pane");
				document.getElementById("layout-container-highlight").style.display = (bShowHighlights ? "table" : "none");
				settings.category["highlight-panel"].setting["visible"].value = bShowHighlights;
			}
			catch(error){ GM_logError(error); }
		},

		toggleDisplayModeLinkClick: function(event)
		{
			try
			{
				settings.category["channel-listing"].setting["view-mode"].value = event.target.innerHTML;
			}
			catch(error){ GM_logError(error); }
		}

	};



// =================================================================================================
// settings
// =================================================================================================

	var settings = {

		category: {},
		get categories() { return this.category; },

		addCategory: function(sName)
		{
		this.category[sName] = {
			name: sName,
			headerText: "",
			setting:{},
			get settings() { return this.setting; },

			addSetting: function(sName, oSetting)
			{
			var oCategory = this;
			this.setting[sName] = {
				category: oCategory,
				name: sName,
				type: oSetting.type,
				defaultValue: oSetting.defaultValue,
				labelText: oSetting.labelText,
				style: oSetting.style,
				get id() { return "userscript-setting--" + this.category.name + "--" + this.name; },
				get value() { return GM_getValue(this.id, this.defaultValue); },
				set value(vValue) { GM_setValue(this.id, vValue); }
				}

			}
		};

		return this.category[sName];
		}

	};




// -------------------------------------------------------------------------------------------------
// identifyElements

	var identifyElements = function() { try
	{

		var a = [];

		a.push({ id:"layout-container-header" , xpath:"/html/body/table[1]" });
		a.push({ id:"header-logo-link" , xpath:"/html/body/table[1]/tbody/tr/td/div/div/a[1]" });
		a.push({ id:"layout-container-highlight" , xpath:"/html/body/table[2]" });
		a.push({ id:"layout-container-highlight-lovetv" , xpath:"/html/body/table[2]/tbody/tr/td[1]" });
		a.push({ id:"layout-container-highlight-gadget" , xpath:"/html/body/table[2]/tbody/tr/td[2]" });
		a.push({ id:"layout-container-body" , xpath:"/html/body/table[3]" });
		a.push({ id:"layout-container-body-datetime" , xpath:"/html/body/table[3]/tbody/tr/td[1]" });
		a.push({ id:"layout-container-body-listing" , xpath:"/html/body/table[3]/tbody/tr/td[2]" });
		a.push({ id:"view-as-grid" , xpath:"/html/body/table[3]/tbody/tr/td[2]/table[1]/tbody/tr/td/table/tbody/tr/td/a[text()='GRID']" });
		a.push({ id:"view-as-list" , xpath:"/html/body/table[3]/tbody/tr/td[2]/table[1]/tbody/tr/td/table/tbody/tr/td/a[text()='LIST']" });
		a.push({ id:"layout-container-footer" , xpath:"/html/body/table[6]" });

		for ( var i = 0, l = a.length ; i < l ; i++ )
		{
			var o = a[i];
			var element = document.getElementByXPath(o.xpath);
			if (element != undefined){ element.setAttribute("id", o.id); }
		}

	}
	catch(error){ GM_logError(error); }};


// -------------------------------------------------------------------------------------------------
// removeElements

	var removeElements = function() { try
	{

		var aXPath = [];

		// ads and ad containers
		aXPath.push("/html/body/div"); // includes strip ad at very top of page, highlight panel ad, vertical ad below date/time selection panel
		aXPath.push("//table[@id='layout-container-footer']/tbody/tr/td[2]/div"); // absolutely positioned header ad
		aXPath.push("//td[@id='layout-container-body-datetime']/a[img]"); // ads above and below date time selection panel
		//aXPath.push("//td[@id='layout-container-body-datetime']/table[2]");
		aXPath.push("//td[@id='layout-container-body-listing']/table[2]/tbody/tr[td/script]"); // ad in first row of listing table
		aXPath.push("//td[@id='layout-container-body-listing']/form/table/tbody/tr/td[4]/*"); // google-ads below channel listings
		aXPath.push("/html/body/table[4]"); // empty table
		aXPath.push("/html/body/table[5]"); // navigation table above footer
		aXPath.push("//iframe[@id='_atssh']"); // iframe ad container

		document.removeElementsByXPath(aXPath.join(" | "));
	}
	catch(error){ GM_logError(error); }};



// -------------------------------------------------------------------------------------------------
// formatDocument

	var formatDocument = function() { try
	{
		var aCSS = [];

		// recolor some elements to give the whole page a black background
		aCSS.push("body { background-color:black; background-image:none; }");
		aCSS.push("table.gridchannel.header { background-color:#000000; }");
		aCSS.push("table.gridchannel.header td { background-color:#333333; border-style:solid; border-width:0px 0px 3px 0px; width:75px; }");

		// reorganise the page header, moving the logo and creating space for additional elements
		aCSS.push("#header-logo-link img { margin-left:-25px; }");
		aCSS.push(".top_logo { padding-right:10px; }");
		aCSS.push(".top_fullbanner { float:right; padding-top:45px; }");
		aCSS.push(".top_fullbanner h1 { color:white; font-family:tahoma,arial,helvetica,san-serif; font-size: 0.7em; padding-bottom:3px; }");

		// make element widths consistent so the whole page fits in 975px
		aCSS.push("#layout-container-body-listing { width:820px; }");
		aCSS.push("div.top_nav { padding:0px; width:975px; }");
		aCSS.push("#layout-container-header { margin:0px auto; width:975px !important; }");
		aCSS.push("#layout-container-highlight { margin:0px auto; width:975px !important; }");
		aCSS.push("#layout-container-body { margin:0px auto; width:975px !important; }");
		aCSS.push("#layout-container-footer { margin:0px auto; width:975px !important; }");
		aCSS.push("ul#menu { width:966px; }");
		aCSS.push("ul#submenus { margin:0px auto; }");
		aCSS.push("#outer { width:975px; }");


		// remove inline style from the highlight pane, and set using classes
		// hide the highlight pane if necessary
		with (document.getElementById("layout-container-highlight"))
		{
			removeAttribute("style");
			style.display = (settings.category["highlight-panel"].setting["visible"].value == true ? "table" : "none");
		}
		aCSS.push("#layout-container-highlight { background-color:black; }");
		aCSS.push("#layout-container-highlight-lovetv { background-color:black; }");
		aCSS.push("#layout-container-highlight-gadget { background-color:black; width:100%; }");


		// create a link to show or hide the highlight panel
		var element = document.createElement("a", { href:"#", onclick:"return false;", style:"float:right; font-size:8pt;",
			innerHTML: ((settings.category["highlight-panel"].setting["visible"].value == true) ? "Hide Highlight Pane" : "Show Highlight Pane") });
		// attach the link to the page header
		var target = document.getElementByXPath("//div[@class='top_fullbanner']");
		target.parentNode.insertBefore(element, target);
		element.addEventListener("click", eventListeners.toggleHighlightDisplayLinkClick, true);



		// create a new category filter table with links spread horizontally instead of vertically,
		// and position in the page header
		var aHTML = [];
		aHTML.push("<h1>Filter current view to see only:</h1>");
		aHTML.push("<table border=\"0\" cellspacing=\"2\" class=\"gridchannel header\" style=\"width:800px;\">");
		aHTML.push("<tbody>");
		aHTML.push("<tr>");
		var sHTML = "<td style=\"border-color:#{0};\"><a href=\"{1}\">{2}</a></td>";
		var tablekey = document.getElementByXPath("//table[@id='tablekey']");

		var categories = [
			{ color:"FFFFFF", name:"All" },
			{ color:"3253CF", name:"Comedy" },
			{ color:"53CE32", name:"Sports" },
			{ color:"FF9933", name:"Music" },
			{ color:"AB337D", name:"Soap" },
			{ color:"E3BB00", name:"Kids" },
			{ color:"CE3D32", name:"Drama" },
			{ color:"800000", name:"Talk Show" },
			{ color:"669999", name:"Game Show" },
			{ color:"666699", name:"Sci-Fi" },
			{ color:"CCCCCC", name:"Documentary" },
			{ color:"996633", name:"Motor" },
			{ color:"666633", name:"Horror" }
		];
		for ( var i = 0, l = categories.length ; i < l ; i++ )
		{
			var category = categories[i];
			var element = document.getElementByXPath("./tbody/tr/td/a[text()='" + category.name + "']", tablekey);
			category.href = (element == null ? "#" : element.getAttribute("href"));
			aHTML.push(String.format(sHTML, category.color, category.href, category.name));
		}
		aHTML.push("</tr>");
		aHTML.push("</tbody>");
		aHTML.push("</table>");
		var target = document.getElementByXPath("//div[@class='top_fullbanner']");
		target.innerHTML = aHTML.join("");
		// remove the original category filter table
		document.removeElementsByXPath("/html/body/table[@id='layout-container-body']/tbody/tr/td[1]/p[table[@id='tablekey']]");


		// create a new row in the body table and reposition the channel filter
		var container = document.getElementByXPath("//table[@id='layout-container-body']/tbody");
		var tr1 = document.createElement("tr");
		var tr2 = document.getElementByXPath("//table[@id='layout-container-body']/tbody/tr[1]");
		tr2.parentNode.insertBefore(tr1, tr2);
		var td = document.createElement("td", { colspan:"2", align:"center" });
		tr1.appendChild(td);
		var channelFilter = document.getElementByXPath("//html/body/table[3]/tbody/tr[2]/td[2]/table");
		td.appendChild(channelFilter);



		// right align times in the date/time selection panel
		var aTarget = document.getElementsByXPath("//td[@id='layout-container-body-datetime']/table/tbody/tr/td/table/tbody/tr[2]/td[2]/table/tbody/tr/td[@class='gridchannel']");
		aTarget.forEach(function(oTarget) { oTarget.setAttribute("align", "right"); });

		// replace negative numbers in date selection with "X days ago"
		var aTarget = document.getElementsByXPath("//td[@id='layout-container-body-datetime']/table/tbody/tr/td/table/tbody/tr[2]/td[1]/table/tbody/tr/td[@class='gridchannel']/a[contains(text(),'-')]");
		aTarget.forEach(function(oTarget) { var s = oTarget.innerHTML; s = s.substring(1, 2) + " days ago"; oTarget.innerHTML = s;  });


		// if viewing in grid view...
		if (nowViewing.viewAs.grid == true)
		{
			// add an event listener to the "view as list" click to store preferences when clicked
			var oTarget = document.getElementById("view-as-list").addEventListener("click", eventListeners.toggleDisplayModeLinkClick, true);
			// prevent text wrapping in the title column of the listings table
			var oTarget = document.getElementByXPath("//td[@id='layout-container-body-listing']/table[1]/tbody/tr[3]/td[1]");
			oTarget.style.whiteSpace = "nowrap";
			oTarget.getElementsByTagName("font")[0].innerHTML = "Click a channel for<br />full day TV listings";
		}

		// if viewing in list view...
		if (nowViewing.viewAs.list == true)
		{
			// add an event listener to the "view as grid" click to store preferences when clicked
			var oTarget = document.getElementById("view-as-grid").addEventListener("click", eventListeners.toggleDisplayModeLinkClick, true);
			document.getElementById("header-logo-link").href += "?view=list";
			document.getElementByXPath("//ul[@id='menu']/li[1]/a").href += "?view=list";
			// make the channel columns fill the available width
			var aTarget = document.getElementsByXPath("//td[@id='layout-container-body-listing']/table/tbody/tr/td[position()>1]/table");
			aTarget.forEach(function(oTarget){ oTarget.parentNode.setAttribute("width", Math.round( 100 / aTarget.length ).toString() + "%"); oTarget.setAttribute("width", "100%"); });
			// ensure that each row of the channel table contains only one cell
			var aTarget = document.getElementsByXPath("//td[@id='layout-container-body-listing']/table/tbody/tr/td[position()>1]/table/tbody/tr/td[2]");
			aTarget.forEach(function(oTarget)
			{
				var oTR = document.createElement("tr");
				oTarget.parentNode.parentNode.insertBefore(oTR, oTarget.parentNode.nextSibling);
				oTR.appendChild(oTarget);
			});
		}

		// identify films in the channel listings, and add a search link to imdb.com (this will take you directly to the film if only the search returns only one result).
		var _buildSearchQuery =
		function(sFilmName)
		{
			var sResult = sFilmName.replace(/^\s+|\s+$/g, ''); //trim the title
			sResult = sResult.replace(/\s/g, "+"); //replace spaces with +'s
			sResult = sResult.replace(/[\?#]!"/g, ""); //remove bad chars
			return escape(sResult);
		};

		var aFilms = document.getElementsByXPath("//td[a/img[@src='/images/film.gif']]");
		for ( var i = 0 ; i < aFilms.length ; i++ )
		{
			var oTD = aFilms[i];
			// get the name of the film
			if (nowViewing.viewAs.grid) { var sFilmName = oTD.getElementsByTagName("a")[0].firstChild.nextSibling.nodeValue; }
			if (nowViewing.viewAs.list) { var sFilmName = oTD.getElementsByTagName("a")[0].getElementsByTagName("img")[0].nextSibling.nodeValue; }
			if (sFilmName.right(3) == "...") return;

			// create a link with the imdb icon to search for the film on imdb in a new tab
			var oImage = document.createElement("img");
			oImage.src =
			"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAsUlEQVR4nK2TQQ4DIQhFheCJupnzdM" +
			"GhWPQ8XbQnsokVqdYhM02MJZlBMe8LqEBEYcVwif6HQM8/pVeeAWMkUA/agwo/eW7ri1QRyDl8YCnfjDcRbDvHjU593G4dsriYQG" +
			"GxT8b6KvC1dL/uYqMI9nQc8MtMkJpACEdZ+IxMVNy8nEJ+sDu+oUm7sTdbQ6tNDgA/9p5rJloCtHrOYXbr3JoKMDymqZuosP7IB2" +
			"Zt+TG9AbL/PkFSMv4WAAAAAElFTkSuQmCC";

			var oAnchor = document.createElement("a");
			oAnchor.href = "http://www.imdb.com/find?s=all&q=" + _buildSearchQuery(sFilmName) + "&x=0&y=0";
			oAnchor.setAttribute("target", "_blank");
			oAnchor.appendChild(oImage);
			oAnchor.style.marginLeft = "5px";

			oTD.appendChild(oAnchor);
		}

			GM_addStyle(aCSS.join("\n"));

		}
		catch(error){ GM_logError(error); }
	};



	var formatDocumentTitle = function()
	{
		try
		{
			// obtain displayed date and time from querystring if present. if not present, we're displaying the current date and time.
			var _getDateTime = function()
			{
				var dtResult = new Date(); dtResult.setMinutes(0); dtResult.setSeconds(0);
				if (location.search != "")
				{
					var s = location.search; s = s.substr(1, s.length);
					var a = s.split("&");
					for ( var i = 0 ; i < a.length ; i++ )
					{
						var b = a[i].split("=");
						if (b[1] != "")
						{
							switch(b[0].toLowerCase())
							{
								case "thisday":
									var c = b[1].split("/");
									dtResult.setFullYear(parseInt(c[2]));
									dtResult.setMonth(parseInt(c[0])-1);
									dtResult.setDate(parseInt(c[1]));
									break;
								case "thistime":
									dtResult.setHours(parseInt(b[1]));
								break;
							}
						}
					}
				}
				return dtResult;
			};

			var dtValue = _getDateTime();
			var s = dtValue.getFullYear() + "-" + ("00" + (dtValue.getMonth()+1)).right(2) + "-" + ("00" + (dtValue.getDate())).right(2);
			document.title = "TV Guide UK TV Listings (" + s + ")";
		}
		catch(error){ GM_logError(error); }
	};




	if (nowViewing.homePage == true)
	{

		with (settings)
		{
			with (addCategory("highlight-panel"))
			{
				addSetting("visible", { type:"boolean" , defaultValue:false  });
			}
			with (addCategory("channel-listing"))
			{
				addSetting("view-mode" , { type:"string" , defaultValue:"GRID" });
			}
		}

		identifyElements();
		removeElements();
		formatDocument();
		formatDocumentTitle();

	}
	GM_log("_@/ tvguide");

}