// ==UserScript== // @name ReleaseBB rlsbb TV Show Tracker // @description Follow TV Shows on rlsbb.ru and swiftly find new episodes // @namespace drdre // @include /^https?:\/\/(www\.)?rlsbb\.com\/$/ // @include /^https?:\/\/(www\.)?rlsbb\.com\/page\/\d+\/?(#.*)?$/ // @include /^https?:\/\/(www\.)?rlsbb\.com\/category\/tv-shows\/(page\/\d+\/?)?$/ // @include /^https?:\/\/(www\.)?rlsbb\.com\/\?s=.+&submit=Find$/ // @include /^https?:\/\/(www\.)?rlsbb\.com\/search/.*$/ // @include /^https?:\/\/(www\.)?rlsbb\.ru\/$/ // @include /^https?:\/\/(www\.)?rlsbb\.ru\/page\/\d+\/?(#.*)?$/ // @include /^https?:\/\/(www\.)?rlsbb\.ru\/category\/tv-shows\/(page\/\d+\/?)?$/ // @include /^https?:\/\/(www\.)?rlsbb\.ru\/\?s=.+&submit=Find$/ // @include /^https?:\/\/(www\.)?rlsbb\.ru\/search/.*$/ // @exclude http://www.rlsbb.ru/maintenance.html // @exclude http://www.rlsbb.com/maintenance.htm // @exclude http://rlsbb.ru/maintenance.html // @exclude http:/rlsbb.com/maintenance.htm // @version 5 // @grant GM_setValue // @grant GM_getValue // @grant GM_xmlhttpRequest // @grant GM_openInTab // @downloadURL none // ==/UserScript== "use strict"; var nukes = ["PROPER","REPACK","RERIP","UPDATE","REAL"]; // ################################# // Production steps of ECMA-262, Edition 6, 22.1.2.1 // Reference: https://people.mozilla.org/~jorendorff/es6-draft.html#sec-array.from if (!Array.from) { Array.from = (function () { var toStr = Object.prototype.toString; var isCallable = function (fn) { return typeof fn === 'function' || toStr.call(fn) === '[object Function]'; }; var toInteger = function (value) { var number = Number(value); if (isNaN(number)) { return 0; } if (number === 0 || !isFinite(number)) { return number; } return (number > 0 ? 1 : -1) * Math.floor(Math.abs(number)); }; var maxSafeInteger = Math.pow(2, 53) - 1; var toLength = function (value) { var len = toInteger(value); return Math.min(Math.max(len, 0), maxSafeInteger); }; // The length property of the from method is 1. return function from(arrayLike/*, mapFn, thisArg */) { // 1. Let C be the this value. var C = this; // 2. Let items be ToObject(arrayLike). var items = Object(arrayLike); // 3. ReturnIfAbrupt(items). if (arrayLike == null) { throw new TypeError("Array.from requires an array-like object - not null or undefined"); } // 4. If mapfn is undefined, then let mapping be false. var mapFn = arguments.length > 1 ? arguments[1] : void undefined; var T; if (typeof mapFn !== 'undefined') { // 5. else // 5. a If IsCallable(mapfn) is false, throw a TypeError exception. if (!isCallable(mapFn)) { throw new TypeError('Array.from: when provided, the second argument must be a function'); } // 5. b. If thisArg was supplied, let T be thisArg; else let T be undefined. if (arguments.length > 2) { T = arguments[2]; } } // 10. Let lenValue be Get(items, "length"). // 11. Let len be ToLength(lenValue). var len = toLength(items.length); // 13. If IsConstructor(C) is true, then // 13. a. Let A be the result of calling the [[Construct]] internal method of C with an argument list containing the single item len. // 14. a. Else, Let A be ArrayCreate(len). var A = isCallable(C) ? Object(new C(len)) : new Array(len); // 16. Let k be 0. var k = 0; // 17. Repeat, while k < len… (also steps a - h) var kValue; while (k < len) { kValue = items[k]; if (mapFn) { A[k] = typeof T === 'undefined' ? mapFn(kValue, k) : mapFn.call(T, kValue, k); } else { A[k] = kValue; } k += 1; } // 18. Let putStatus be Put(A, "length", len, true). A.length = len; // 20. Return A. return A; }; }()); } function pad2(i) { if(i < 10 && i > -10) { return "0"+parseInt(i,10) } return ""+parseInt(i,10); } function int(s) { return parseInt(s,10); } function float(s) { return parseFloat(s); } function trim(str) { return str.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); } function parseMonthname(name) { var o = {"month": "long"}; for(var i = 0; i < 12; i++) { if((new Date(i*2678400000)).toLocaleDateString("en-US", o) == name) { return i; } } return -1; } function humanBytes(bytes, precision) { bytes = parseInt(bytes,10); if(bytes === 0) return '0 Byte'; var k = 1024; var sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; var i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toPrecision(2)) + ' ' + sizes[i]; } function base64BinaryString(s) { const base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; const l = s.length; var o = []; var char0,char1,char2,char3; var byte0,byte1,byte2; var t; var i = 0; while(i < l) { byte0 = s.charCodeAt(i++) & 0xff; byte1 = i> 2; char1 = ((byte0 & 0x3) << 4) | (byte1 >> 4); char2 = ((byte1 & 0x0f) << 2) | (byte2 >> 6); char3 = byte2 & 0x3f; t = i - (l - 1); if(t == 1) { char3 = 64; } else if(t == 2) { char3 = 64; char2 = 64; } o.push(base64.charAt(char0), base64.charAt(char1), base64.charAt(char2), base64.charAt(char3)); } return o.join(""); } function loadCrossSiteImage(url,cb) { var canvas = document.createElement("canvas"); var ctx = canvas.getContext("2d"); var img0 = document.createElement("img"); // To get image dimensions img0.addEventListener("load",function(){ if(img0.height == 0 || img0.width == 0) return; canvas.height = img0.height; canvas.width = img0.width; GM_xmlhttpRequest ({ method: 'GET', overrideMimeType: 'text/plain; charset=x-user-defined', url: url, // Load cross site image into canvase onload: function (resp) { var dataurl = "data:image/jpeg;base64," + base64BinaryString(resp.responseText); var img1 = document.createElement("img"); // Image is already data url, but let's compress it a little bit img1.addEventListener("load",function(){ ctx.drawImage(img1, 0, 0); cb(url,canvas.toDataURL("image/jpeg",0.2)); }); img1.src = dataurl; } }); }); img0.src = url; } // ################################# var libversion = false; var lastlibversion = false; var records; var ignoreShows; var mapID2Index = {}; // temporary cache for finding an entry by its ID i.e. unique URL function load() { libversion = int(GM_getValue("libversion",Number.MIN_SAFE_INTEGER)); if(lastlibversion == libversion) return; records = JSON.parse(GM_getValue("records","[]")); ignoreShows = new Set(JSON.parse(GM_getValue("ignoreShows","[]"))); lastlibversion = libversion; mapID2Index = {}; } function save() { if(libversion === false) { throw Error("save() cannot be called before load()"); } libversion++; if(libversion == Number.MAX_SAFE_INTEGER) { libersion = Number.MIN_SAFE_INTEGER; } GM_setValue("libversion",libversion); records = sortRecords(records); GM_setValue("records",JSON.stringify(records)); GM_setValue("ignoreShows",JSON.stringify(Array.from(ignoreShows))); lastlibversion++; } function getRecordById(id) { if(mapID2Index[id]) { return records[mapID2Index[id]]; } for(var i = 0; i < records.length; i++) { if(records[i].id == id) { mapID2Index[id] = i; return records[i]; } } return false; } function Episode(episode) { load(); if(typeof episode == "string") { return getRecordById(episode); } else if("id" in episode) { return getRecordById(episode.id); } else { throw new Error("Wrong format episode:"+JSON.stringify(episode)); } } function isDownloaded(id) { var record = Episode(id); return record.hasOwnProperty("downloaded") && record.downloaded; } function setDownloaded(id) { var record = Episode(id); record.downloaded = true; save(); } function isIgnoredShow(id) { var record = Episode(id); if(record.show && ignoreShows.has(record.show)) { return true; } return false; } function ignoreShow(id) { if(isIgnoredShow(id)) { return true; } else { var record = Episode(id); if(record.show) { ignoreShows.add(record.show); save(); return true; } } return false; } function unIgnoreShow(id) { if(!isIgnoredShow(id)) { return true; } else { var record = Episode(id); if(record.show) { if(!ignoreShows.has(record.show)) { return true; } else { ignoreShows.delete(record.show); save(); return true; } } } return false; } function toggleIgnoreShow(id) { if(isIgnoredShow(id)) { if(unIgnoreShow(id)) { return 1; } } else { if(ignoreShow(id)) { return -1; } } return 0; } function removeIgnoredShowsFrom(arr) { var narr = arr.filter(function(record){ return record.show && !ignoreShows.has(record.show); }); return narr; } function sortRecords(arr) { var narr = arr.slice(0); narr.sort(function(a,b) { return b.time - a.time; }); return narr; } function sortRecordsByTitle(arr) { var narr = arr.slice(0); narr.sort(function(a,b) { return a.title.localeCompare(b.title); }); return narr; } function getLatestEpisodes() { load(); var episodes = {}; for(var i = 0; i < records.length; i++) { if(("show" in records[i]) && (!(records[i].show in episodes) || episodes[records[i].show].time <= records[i].time)) { episodes[records[i].show] = records[i]; } } return Object.keys(episodes).map(function (show) { return episodes[show]; }); } function readPost(post) { var entryContent = post.getElementsByClassName("entry-content")[0]; var link = post.getElementsByClassName("postTitle")[0].getElementsByTagName("a")[0]; var subtitle = post.getElementsByClassName("postSubTitle")[0]; var id = link.href; var upperCaseContent = entryContent.innerHTML.toUpperCase(); var isnuke = false; if(getRecordById(id) !== false) { if(0 == Array.filter(nukes,function(a) { return -1!=upperCaseContent.indexOf(a)}).length) { throw "error_recordexists"; return; } else { // It's a nuke isnuke = true; } } var time = subtitle.innerHTML.match(/Posted on (\D+) (\d+)\D\D, (\d{4}) at (\d+):(\d{2}) (am|pm)/); // Posted on August 17th, 2014 at 10:47 pm var title = trim(link.innerHTML); var result = { "id": id, "title": title, "time": (new Date(int(time[3]), parseMonthname(time[1]),int(time[2]), int(time[4])+(time[6] == 'pm'?12:0), int(time[5]), 0, 0)).getTime(), "release" : [] }; var tvshow; if((tvshow = title.match(/^(.*)\s(\d+)\xD70*(\d+)\s/)) || (tvshow = title.match(/^(.*)\sS0*(\d+)E0*(\d+)\s/) )) { result["show"] = trim(tvshow[1]).toLowerCase(); result["showWithCase"] = trim(tvshow[1]); result["season"] = int(tvshow[2]); result["episode"] = int(tvshow[3]); } // Find actual releasenames of movie var strong = entryContent.getElementsByTagName("strong"); for(var i = 0; i < strong.length; i++) { if(strong[i].innerHTML.match(/Release Name:/)) { result["release"].push(trim(strong[i].nextSibling.textContent)); } else if(strong[i].innerHTML.match(/Links:/)) { var a = strong[i].parentNode.getElementsByTagName("a"); var m; for(var j = 0; j < a.length; j++) { if(m = a[j].href.match(/imdb\.com\/title\/(\w+)/)) { result["imdb"] = m[1]; break; } } } } // Find actual releasenames of tvshow var strong = entryContent.getElementsByTagName("strong"); for(var i = 0; i < strong.length; i++) { var m; if((m = strong[i].innerHTML.match(/\.(\d+)\xD70*(\d+)\./)) || (m = strong[i].innerHTML.match(/\.S0*(\d+)E0*(\d+)\./) )) { result["release"].push(trim(strong[i].innerHTML)); } } // Find tvshow image var img = false; if(entryContent.getElementsByTagName("p").length) { if(entryContent.getElementsByTagName("p")[0].getElementsByTagName("img").length) { img = entryContent.getElementsByTagName("p")[0].getElementsByTagName("img")[0]; } } if("show" in result && img) { result["image"] = img.src; } if("show" in result || "imdb" in result) { // Only save tvshows or movies if(isnuke) { records[mapID2Index[id]] = result; // Overwrite record } else { records.push(result); // New record } } } function readPosts() { load(); var error_recordexists = false; var posts = document.getElementsByClassName("entry post"); for(var i = 0; i < posts.length; i++) { try { readPost(posts[i]); } catch(e) { if(e == "error_recordexists") { error_recordexists = true; } else { throw e; } } } save(); if(error_recordexists) { throw "error_recordexists"; } } function crawl() { if(document.location.href.indexOf("#crawlbackto=") == -1) { if(!confirm("Start scanning?\nTo stop the process you'll have to close the tab/window!")) { return false; } } var url = document.getElementById("olderEntries").getElementsByTagName("a")[0].href+"#crawlbackto=-1"; document.location.href = url; } var mw; function getMainWindow() { const id = "rlsbbmymainwin"; if(mw) { return mw; } mw = {}; mw.main = document.createElement("div"); mw.main.id = id; mw.main.style = "position:fixed; top:0px; left:0px; z-index:999"; document.body.appendChild(mw.main); mw.controls = document.createElement("div"); mw.main.appendChild(mw.controls); mw.menu = document.createElement("div"); mw.menu.setAttribute("style","overflow:auto; margin-top:1px; margin-bottom:3px; max-height:"+(window.innerHeight-150)+"px; background: -moz-linear-gradient(center top , #eee, #bbb) repeat scroll 0 0 #ccc;"); mw.main.appendChild(mw.menu); mw.lists = document.createElement("div"); mw.lists.setAttribute("style",""); mw.main.appendChild(mw.lists); return mw; } function showButton(title,click) { var c = getMainWindow().controls; var br = c.getElementsByTagName("br"); if(br.length) { br = br[br.length-1]; } else { br = document.createElement("br"); br.style = "clear:left"; c.appendChild(br); } var b = document.createElement("div"); b.style = "cursor:pointer; border-radius: 5px 5px 0 0; color: black; background: -moz-linear-gradient(center top , #eee, #bbb) repeat scroll 0 0 #ccc; text-shadow: 1px 1px 0 #eee;\ float: left; padding:2px 4px 1px; margin: 2px; height: 20px; text-align: center; font-size: 14px;"; b.addEventListener("click",click); b.addEventListener("mouseover",function() { this.dataset.oldbgImage = this.style.backgroundImage; this.style.backgroundImage = "-moz-linear-gradient(center top , #fff, #bbb)"; }); b.addEventListener("mouseout",function() { if(this.dataset.oldbgImage) this.style.backgroundImage = this.dataset.oldbgImage; }); b.innerHTML = title; c.insertBefore(b,br); } function showIgnoreMenu() { var c = getMainWindow().menu; c.innerHTML = ""; if(c.dataset.menu == "ignore") { c.dataset.menu = ""; return; } else { c.dataset.menu = "ignore"; } var allshows = getLatestEpisodes(); allshows = sortRecordsByTitle(allshows); var ul = document.createElement("ul"); var li; var lis = []; // Search by key var search = function(s) { for(var i = 0; i < lis.length; i++) { if(lis[i].textContent.toLowerCase().startsWith(s)) { lis[i].scrollIntoView(); window.scrollY = 0; return; } } }; var search_it = false; var search_str = ""; var keyup = function(ev) { search_str += ev.key; search(search_str); if(search_it !== false) { clearTimeout(search_it); } search_it = setTimeout(function() { search_str = ""; },2000); }; document.body.addEventListener("keyup",keyup,false); var toggle = function(ev) { var id = this.dataset.id; var status = toggleIgnoreShow(id); if(status == 1) { this.style.background = "#99CC99"; } else if(status == -1) { this.style.background = "red"; } else { this.style.background = "yellow"; alert("An error occurred. Try reloading the page."); } }; var ignoreAll = function(ev) { if(!confirm("Really ignore all shows?")) return; var allshows = getLatestEpisodes(); for(var i = 0; i < allshows.length; i++) { ignoreShow(allshows[i].id); } document.location.reload(); }; var showAll = function(ev) { for(var i = 0; i < lis.length; i++) { ul.removeChild(lis[i]); } lis = []; for(var i = 0; i < allshows.length; i++) { li = document.createElement("li"); li.setAttribute("data-id",allshows[i].id); li.appendChild(document.createTextNode(allshows[i].showWithCase+" S"+ pad2(allshows[i].season)+"E"+pad2(allshows[i].episode))); if(isIgnoredShow(allshows[i].id)) { li.style.background = "red"; } else { li.style.background = "#99CC99"; } li.addEventListener("click",toggle,false); ul.appendChild(li); lis.push(li); } }; var b; b = document.createElement("button"); b.innerHTML = "Show all"; b.addEventListener("click",function() {showAll();},false); c.appendChild(b); b = document.createElement("button"); b.innerHTML = "Ignore all"; b.addEventListener("click",function() {ignoreAll();},false); c.appendChild(b); for(var i = 0; i < allshows.length; i++) { if(isIgnoredShow(allshows[i].id)) { continue; } li = document.createElement("li"); li.setAttribute("data-id",allshows[i].id); li.appendChild(document.createTextNode(allshows[i].showWithCase+" S"+ pad2(allshows[i].season)+"E"+pad2(allshows[i].episode))); if(!isDownloaded(allshows[i])) { li.style.background = "white"; // New show } else { li.style.background = "#99CC99"; // Old show that is not ignored } li.addEventListener("click",toggle,false); ul.appendChild(li); lis.push(li); } c.appendChild(ul); } function showCleanMenu(forceshow) { // Toggle Clean Menu var c = getMainWindow().menu; c.innerHTML = ""; if(c.dataset.menu == "clean" && forceshow !== true) { c.dataset.menu = ""; return; } else { c.dataset.menu = "clean"; } loadImageCache(); var allshows = getLatestEpisodes(); var ul = document.createElement("ul"); var clearButKeepEpisodes = function(ev) { load(); records = records.filter(function(record){ return "show" in record && record.show; }); save(); showCleanMenu(); }; var clearButKeepEpisodesDeleteIgnored = function(ev) { load(); records = records.filter(function(record){ return "show" in record && record.show && !ignoreShows.has(record.show); }); save(); showCleanMenu(true); }; var clearAllImageCache = function(ev) { GM_setValue("imageCache","{}"); loadImageCache(); showCleanMenu(true); }; var clearImageCacheButKeepEpisodes = function(ev) { loadImageCache(); var episodes = getLatestEpisodes(); episodes = removeIgnoredShowsFrom(episodes); var newImageCache = {} for(var i = 0; i < episodes.length; i++) { if(episodes[i].image) { var url = episodes[i].image; if(imageCache[url]) { newImageCache[url] = imageCache[url]; } } } GM_setValue("imageCache",JSON.stringify(newImageCache)); loadImageCache(); showCleanMenu(true); }; var b,li; li = document.createElement("li"); li.appendChild(document.createTextNode("Cleaning options:")) c.appendChild(li); li = document.createElement("li"); b = document.createElement("button"); b.innerHTML = "Keep TV Shows"; b.addEventListener("click",function() {clearButKeepEpisodes();},false); li.appendChild(b) c.appendChild(li); li = document.createElement("li"); b = document.createElement("button"); b.innerHTML = "Keep TV Shows (delete ignored shows)"; b.addEventListener("click",function() {clearButKeepEpisodesDeleteIgnored();},false); li.appendChild(b) c.appendChild(li); li = document.createElement("li"); b = document.createElement("button"); b.innerHTML = "Clear image cache"; b.addEventListener("click",function() {clearAllImageCache();},false); li.appendChild(b) c.appendChild(li) li = document.createElement("li"); b = document.createElement("button"); b.innerHTML = "Clear image cache (keep tracked TV Shows)"; b.addEventListener("click",function() {clearImageCacheButKeepEpisodes();},false); li.appendChild(b) c.appendChild(li) li = document.createElement("li"); b = document.createElement("input"); b.value = allshows.length +" TV shows"; b.disabled = 1; li.appendChild(b) c.appendChild(li); li = document.createElement("li"); b = document.createElement("input"); b.value = records.length +" total records"; b.disabled = 1; li.appendChild(b) c.appendChild(li); li = document.createElement("li"); b = document.createElement("input"); b.value = Object.keys(imageCache).length +" images ("+humanBytes(GM_getValue("imageCache","").length)+")"; b.disabled = 1; li.appendChild(b) c.appendChild(li); c.appendChild(ul); } var imageCache; function loadImageCache() { imageCache = JSON.parse(GM_getValue("imageCache","{}")); } function cacheImage(url,dataurl) { imageCache[url] = dataurl; GM_setValue("imageCache",JSON.stringify(imageCache)); } function showTVShows() { loadImageCache(); var c = getMainWindow().lists; var div = document.createElement("div"); div.setAttribute("style","max-height:"+(window.innerHeight-150)+"px; overflow:auto; border-bottom-right-radius: 5px; border-bottom-left-radius: 5px;") var openEpisode = function() { if(this.dataset.episodeid) { var record = Episode(this.dataset.episodeid); //window.open("http://www.rlsbb.com/?s=%22"+encodeURIComponent(record.showWithCase)+"%22&submit=Find"); //window.open("http://rlsbb.com/search/"+encodeURIComponent(record.showWithCase)+"?first"); GM_openInTab(this.dataset.episodeid); setDownloaded(this.dataset.episodeid); // Mark grey and remove new tag this.style.borderColor = "silver"; this.style.color = "silver"; this.removeChild(this.querySelector(".newtag")); this.removeChild(this.querySelector(".ignorebutton")); } }; var div_header = document.createElement("div"); var bg = "background: -moz-linear-gradient(center top , #eee, #bbb) repeat scroll 0 0 #ccc;"; div_header.style = bg+"cursor:pointer;"; div_header.appendChild(document.createTextNode("TVShows")); div.appendChild(div_header); var div_select = document.createElement("div"); div_select.style.display = "none"; div.appendChild(div_select); div_header.addEventListener("click",function(ev) { // Show/Load TV episodes if(div_select.style.display == "block") { div_select.style.display = "none"; return; } div_select.style.display = "block"; if(div_select.children.length > 1) { return; } var episodes = getLatestEpisodes(); episodes = removeIgnoredShowsFrom(episodes); episodes = sortRecords(episodes); var onLoadBackgroundImage = function() { var entry = this.parentNode; var w = float(entry.clientWidth); var img = this; if(!img.width || !img.height) { entry.removeChild(img); return; // Something is wrong with the image! } entry.style.background = "no-repeat url('"+img.src+"') white"; var h = Math.ceil(w * (float(img.height)/ float(img.width))); entry.style.height = h+"px"; entry.style.backgroundSize = w+"px "+h+"px"; entry.removeChild(img); }; var entries = []; for(var i = 0; i < episodes.length; i++) { var entry = document.createElement("div"); entries.push(entry) entry.dataset.episodeid = episodes[i].id; entry.appendChild(document.createTextNode(episodes[i].showWithCase+" S"+ pad2(episodes[i].season)+"E"+pad2(episodes[i].episode))); entry.addEventListener("click",openEpisode); div_select.appendChild(entry); entry.style = bg+" margin:3px 10px 3px; min-width:200px; min-height:20px; font-weight:bolder; text-shadow:1px -1px 5px white;"; if(!isDownloaded(episodes[i])) { // New episode entry.style.textShadow = "1px -1px 5px black"; entry.style.color = "#ff2"; entry.style.borderStyle = "solid"; entry.style.borderColor = "rgba(255, 255, 0, 0.4) yellow" entry.style.borderWidth = "1px 1px 1px 6px"; // NEW tag var div_new = document.createElement("div"); div_new.setAttribute("class","newtag"); div_new.style = "display: inline-block; margin-top:20px; -3px -3px 8px white; background: rgba(255, 255, 0, 0.6); border: 2px solid black; color: black; font-family: comic sans ms; font-weight: normal; border-radius:20px 5px 5px 50px; padding:0 2px 0 6px; "; if(episodes[i].image) { div_new.style.transform = "rotate("+(310+Math.ceil(Math.random()*20))+"deg)"; } div_new.appendChild(document.createTextNode("\u309C NEW")); //゜ entry.appendChild(div_new); // Ignore button var div_ign = document.createElement("div"); div_ign.setAttribute("class","ignorebutton"); div_ign.style = "margin-top: 0px; margin-left:220px; text-shadow:1px -1px 5px white; color:silver; cursor:pointer; "; div_ign.appendChild(document.createTextNode("\u2717")); //✗ div_ign.addEventListener("click",function(ev) { ev.stopPropagation(); if(confirm("Ignore?")) {if(ignoreShow(this.parentNode.dataset.episodeid)) { this.parentNode.parentNode.removeChild(this.parentNode); } else { alert("An error occured!"); } } }); entry.insertBefore(div_ign,entry.firstChild); } if(episodes[i].image) { var url = episodes[i].image; if(imageCache[url]) { url = imageCache[url] } else { loadCrossSiteImage(url,cacheImage); } var img = document.createElement("img"); img.addEventListener("load",onLoadBackgroundImage); img.src = url; // Preload background image to get size img.style = "max-width:180px; display:none"; entry.appendChild(img); } else { entry.style.borderStyle = "solid"; entry.style.borderWidth = "1px"; } } }); c.appendChild(div); } function page_articles() { var error_recordexists = false; try { readPosts(); } catch(e) { if(e == "error_recordexists") { error_recordexists = true; } else { throw e; } } var crawlback; if(crawlback = document.location.hash.match(/crawlbackto=(-?\d+)/)) { if(!error_recordexists) { var end = int(crawlback[1]); if(!document.location.href.match(new RegExp("page\/"+end+"\/"))) { document.title = "Crawling..."; crawl(); return; } } else { document.title = "Scanning finished!"; alert("Scanning finished!"); } } showTVShows(); showButton("Scan",crawl); showButton("Ignore",showIgnoreMenu); showButton("Clean",showCleanMenu); } function page_searchresults() { var m = document.body.firstChild.textContent.match(/Please try again in (\d+) seconds./); if(m) { window.setTimeout(function() { document.location.reload() },3000+int(m[1])*1000); } } (function() { if(document.location.href.endsWith("&submit=Find") || document.location.href.indexOf("/search/") != -1) { page_searchresults(); } else { page_articles(); } })();