User:Phlip/Greasemonkey
From Homestar Runner Wiki
// If you want to install this script, then (if you don't have them already) you'll need to install Firefox and Greasemonkey, then restart Firefox and return to this page.
// Then, just click on this link to install the script.
// Homestar All-In-One // version 3.2 // 2006-09-27 // Copyright (c) Phillip Bradbury, Loafing, T Rice, Jesse Ruderman // // A combination of several useful scripts for Homestar Runner cartoons: // Homestar-Fullon, a greasemonkey script for making H*R cartoons fullscreen. // Seek Bar, a bookmarklet that adds a progress bar to flash cartoons // (with modifications). // Previous/Next buttons for Strong Bad Emails, TGS, Marzipan's // Answering Machine, Biz Cas Fri, Puppet Jams and main pages. // An HRWiki link on all pages. // The ability, if you turn on the "fullscreen" option, to keep the actual // stage the same size (so you can see "outside the frame"). // Turning everything upside-down, like on April Fools Day, 2006. // A plain-HTML navbar, to replace the Flash one. This is mostly for me // as the navbar doesn't work right on my computer (font problems). // It could also be useful for others, letting you middle-click the navbar // to open things in new tabs. // Loading subtitles from the wiki and displaying them beneath the toon. // All of these can easily be turned on or off with the "Preferences" box // in the top left. // // Released under the GPL. // // Homestar-Fullon written by T Rice <timgm@bcheck.net> and is // released under the GPL. // http://dana.ucc.nau.edu/~tsr22/apps/greasemonkey/ // // Seek bar written by Jesse Ruderman <jruderman@hmc.edu> and is // distributed with permission ("You may modify and/or distribute // up to three bookmarklets from this site in any way you want.") // http://www.squarefree.com/bookmarklets/ // Originally it was just the Pause button and the seek bar, // I modified it to add a frame counter, frame step buttons and zoom buttons. // I also modified it so the Pause button automatically updates when the flash // movie pauses itself (eg at the end of the toon). // // Previous/Next buttons written by Phillip Bradbury, but inspired by // StrongBad Emails: Prev & Next from http://userscripts.org/scripts/show/1015 // // HRWiki link also written by Phillip Bradbury, but inspired by an attempt // by Tom Preuss to do the same thing - except it did the translation from // URL to Wiki page name in the script, this does it at the HRWiki server // so that when a new toon comes out, the script doesn't need to be changed. // http://www.hrwiki.org/wiki/User:Tom/Greasemonkey_Script // // Subtitles written in collaboration with "Loafing" // http://www.hrwiki.org/wiki/User:Loafing // // Direct any comments to // http://www.hrwiki.org/wiki/User_talk:Phlip/Greasemonkey // // -------------------------------------------------------------------- // // WARNING: This script explicitly avoids use of one of Greasemonkey's security // features. THIS SCRIPT SHOULD NOT BE USED on ANY page where you do not trust // the page writer. Not that it would make sense to anyway, given it's rather // Homestar-specific. Your use of this script is stating that you trust // The Brothers Chaps to not insert malicious code into the Homestar Runner site, // and the HRWiki admins to not put any on the mirror. // // One of the security features of Greasemonkey, used to plug its holes in // previous versions, is Mozilla's XPCNativeWrapper, which is used to ensure // that you're calling the real functions of objects on the page, and not // weird and potentially hazardous ones written by the page designer. However // this also blocks functions like flashmovie.CurrentFrame() which are needed // by the seek bar. Thus to make the seek bar work, I needed to turn this off. // // -------------------------------------------------------------------- // // This is a Greasemonkey user script. // // To install, you need Greasemonkey: http://greasemonkey.mozdev.org/ // Then restart Firefox and revisit this script. // // To uninstall, go to Tools/Manage User Scripts, // select "Homestar All-In-One", and click Uninstall. // // -------------------------------------------------------------------- // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // -------------------------------------------------------------------- // // ==UserScript== // @name Homestar All-In-One // @namespace http://www.hrwiki.org/ // @description Combination of many Homestar Runner scripts. Version 3.2. // @include http://homestarrunner.com/* // @include http://www.homestarrunner.com/* // @include http://podstar.homestarrunner.com/* // @include http://videlectrix.com/* // @include http://www.videlectrix.com/* // @include http://hrwiki.org/mirror/* // @include http://www.hrwiki.org/mirror/* // @include https://secure.homestarrunner.com/heythanks.html* // @grant GM_getValue // @grant GM_setValue // @grant GM_xmlhttpRequest // @grant GM_addStyle // @grant unsafeWindow // ==/UserScript== // Returned by Special:Getversion // <versionstring>3.2.11=http://www.hrwiki.org/w/index.php?title=User:Phlip/Greasemonkey&action=raw&ctype=text/javascript&fakeextension=.user.js</versionstring> var currentversion = [3,2,11]; // Podstar/Videlectrix (stock IIS), HRWiki and stock Apache error pages, respectively. Don't do anything on those pages. if (document.title != "The page cannot be found" && document.title != "Homestar Runner Wiki - 404 Not Found" && document.title != "404 Not Found") { var whichsite = 0; if (location.hostname.indexOf("podstar") >= 0) whichsite = 1; if (location.hostname.indexOf("videlectrix") >= 0) whichsite = 2; if (location.pathname.indexOf("/mirror/") >= 0) whichsite = 3; // icons, as Base64-encoded PNG files. // the hrwiki one used to hotlink http://www.hrwiki.org/favicon.ico but now // use "data:" to avoid bandwidth-leeching (even this minor) var image_hrwiki = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQ" + "CAMAAAAoLQ9TAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAm1QTFR" + "F////2wAzgZDJAiGNAB6Lenp6ABCEABKFAAyDjp3O8gAAipjLlaPPFUixAB6OAA6C/f//fY" + "3JABaIhJXK///50gAn///4CymXyQAaAA+DOFCm1QAmDiuX//zvnV2IfI3IQ0h7ABSFN0+qZ" + "Xm9ABSG9PTxABiK2wAkuQAdSWW5WGu4cILCgYy209PZGRdjABeH0AALDiyYASGOhJTL2bi8" + "k5OTzgAj1QAdLkilAAiDABiQIiCBzwAbyAAk//31ABSO0gAXDB95c5nZDAxeoRhHOVCp7u3" + "lfx1W1LrCxQYtwwApQVitwAQpJj2bAAyFKSODfI3GYna86urqysfL9fT0NUyXMDGGNk6cxg" + "ASy9rkAB2OQ1qzTmOzu8Pa4d/b+v//58zRFEqw09XR25yrIjyh9P//g5PLAAN+foy/uRY92" + "treh6neAASDXXC9jJvKjJvL6enpiJfKDzejNk6r2wE1N0+rABKEAB6KxAAn0tPWyQAZRFuv" + "XXfB/f392AAgKiib2QAyABaJhJTH2XeNEy+ZzgAwBiSRKUOlgI27urrP7t/iCghS0AAfk3S" + "oyBc+iChf3vH1VWq426GvgI/HizduboDCPEOXABCDSmu/DyeD///6P2K4OUJ/HByRlKHOAB" + "+O8AAA2QI1hZPHg5TI9PT0ABuJiZjM1tbdf43CzgApAB2We4vD7e3rwgAseInHAyGWi5rOU" + "me3hIuqFTGaWG25dojDd5LQ5Ki1AAyMASCNcYHEAyKOABqLACSWHDeR+vr6uwAiIyBjipnJ" + "1AIyjZvMmJyaITylAByMAB2L5wAlHDeeCCaUcHCjWGy4wBQy/7AMAgAAARFJREFUeNpiONF" + "euLWjfL4RM1/R4tXyx5kZdrNHZ8za5DjT3n/KimUtLDsZhPbFJilY14d5cC3o1dRnaWPILa" + "ucozf3DAND3DmnxqWnmRjyd+046NzJwGB6dMJ6xVNHJjPIrGvq1mVgYGBlZQg9xjlxD4MKh" + "2+wKgMILLET00mPYmCqFpctYIAAEamz3AzaG4TdgmohAllpgsoMbBw5y9fshwiEW0qyM7jG" + "bIlMjWcQCOlKMKnR8rZgyDOe3e95oErCJqLOPDGQ8xBDCv8qF9tWRkb1SStPTvNTU2JgK83" + "OrDjMaKbB0Gwgt23zdIap83h9vBZKJ4MMdZ/Bs5EhwHBvz9qSBoftDAx9olbFiwACDABkK1" + "N43Z86KwAAAABJRU5ErkJggg=="; var image_prefs = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQC" + "AMAAAAoLQ9TAAAAllBMVEUAGQASEhIfHx8fJy8pKSk2NjZBQUFJR0ZQUE9RUVFSUlJNX3No" + "aGhsaWdramlycG1meY98fHx+fn5wgpV0iqKKh4R4jaR9jJx8kad9kad/mbONmaWEnrmEnrq" + "koZy3t7fIx8bKyMHT0c3S0dDU09DV1NPP1t3W1dXY2Njb2tfe29bf3tzj4uHr6+js6+r39/" + "f5+PgAAABrL3yvAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxMAAAsTA" + "QCanBgAAAAHdElNRQfWBRoFKh31UQ8DAAAAgUlEQVQY022OxxLCMAwFRSc4BEIPJZQQ08v+" + "/8+RsTExDDpIe3ijfSJ/hx9g62Dt4GaAI+8YT0t27+BxxvvE/no5pYT10lGFrE34Ja40W3g" + "1oMGmW7YZ6hnCYexKTPVkXivuvWe1Cz1aKqPNI3N0slI2TNYZiARJX30qERc7wBPKC4WRDz" + "WdWHfmAAAAAElFTkSuQmCC"; var image_close = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQC" + "AQAAAC1+jfqAAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfW" + "BRkTNhxuPxLkAAAAHXRFWHRDb21tZW50AENyZWF0ZWQgd2l0aCBUaGUgR0lNUO9kJW4AAAE" + "KSURBVCjPhdGxSgNBFAXQMzpgYWwsLEQUDBJBQgqFIChZEPR7/DA/QCGQTgQtJE1ENoWohY" + "UgbGKQyFjErNv52nObe19wqGWg7z0l5YVgVdOu+wUt507tqIVQ4Zodp861ooELe15M5KFI6" + "Zfr9u25MIj6Jl4cmSIPBWrq2o5cufO4aOJDYSozNTa2pK4t03PtwUdMKRRykAmW0dTRcyNX" + "pBQpI8GJDTR050zkNzK0bMMZLvUNZ8yCfy6Wvbc1NVyi4dloXjqWvds6uvp41pFmpVOKJWd" + "6bgwxkmTMIotWKpwrfBkZl7uMonUHf5wSlV2+fUZrjnXdzrmyy7djD8GWTW9e51z557o1Tz" + "85FH/WkOkaHQAAAABJRU5ErkJggg=="; var image_update = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEYAAABG" + "CAMAAABG8BK2AAAC8VBMVEUAAAD/AAD+AQH/AQH/AgL+AwP/AwP+BAT/BAT/BQX+Bgb/Bgb" + "/Bwf+CAj/CAj/CQn/Cgr+Cwv/Cwv+DAz/DAz/DQ3/Dg7+Dw//Dw//EBD+ERH/ERH/EhL/Ex" + "P+FBT/FRX/Fhb/Fxf+GBj/GBj/GRn/Ghr/Gxv/HBz/HR3/Hh7/Hx//ICD+ISH/ISH/IiL/I" + "yP/JCT/JSX/Jib/Jyf/KSn/Kyv/LCz/LS3/Ly//MDD/MTH+MjL/MjL/MzP/NDT/NTX/Njb+" + "Nzf/Nzf/ODj+OTn/OTn/Ojr/PDz/Pj7/Pz//QUH/QkL+Q0P/RUX/Rkb/R0f/SEj/SUn/Skr" + "/S0v/TEz/TU3/Tk7/T0//UFD/UVH/UlL/VFT/VVX/Vlb/WFj/WVn/Wlr/W1v/XFz/XV3/Xl" + "7/X1//YGD/YWH/YmL/Y2P/ZWX/Zmb/Z2f/aGj/aWn/amr/a2v/bGz/bW3/bm7/b2//cHD/c" + "XH/cnL/dHT/dnb/d3f/eHj/eXn/e3v/fX3/fn7/f3//gID/gYH/goL/g4P/hIT/hob/h4f/" + "iIj/iYn/ior/i4v/jIz/jY3/jo7+kJD/kJD/kZH/kpL/lJT/lpb/l5f/mJj/mZn/mpr/m5v" + "/nJz/nZ3/n5//oKD/oaH/oqL/o6P/pqb/p6f/qKj/qan/qqr/q6v/rKz/ra3/r6//sLD/sb" + "H/srL/s7P/tLT/tbX/trb/t7f/uLj/urr/u7v/vLz/vb3/vr7/v7//wMD/wcH/wsL/w8P/x" + "MT/xcX/xsb+x8f/x8f/yMj/ycn/ysr/y8v/zMz/zc3/zs7/z8//0ND/0dH/0tL/09P+1NT/" + "1NT/1tb/19f+2Nj/2Nj/2dn/29v/3Nz/3d3/39//4OD/4eH/4uL/4+P/5OT/5eX/5ub/5+f" + "/6Oj/6en/6ur/6+v/7Oz/7e3/7u7/7+/+8PD/8fH/8vL/8/P/9PT/9fX/9vb/9/f/+Pj/+f" + "n/+vr/+/v//Pz//f3+/v7//v7////+AAA5GkRyAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFH" + "UgAAAAJcEhZcwAADzoAAA+IAUHKF/gAAAAHdElNRQfXCRYICgxGxxkcAAAEL0lEQVRYw63X" + "e1wURRwA8Pm1G0KcHdGBkKAYjxC0yLJITUl7cr7RUjAos4AuraCH2pWCVlZaRpD5AEXDwAe" + "mQRFdmgQeCgWUPKTk4JJHomAq5PBXu/fC2zt2Z7fdf+Y38/nc9zPz+83M7iEQ9VBDjCNxSt" + "KGG5xJSBSjWPV+c3m0nxNFDEP/XBf3ZkPLuvGOigiG2oLrhyvVJX26abdzFXKGWtrUPRXA5" + "aasRjyD5ijkzJjd/2aMNkXqhCiKoxAzU9bg3nmDdXe1V4iZJIzTBnvhH9xrpxAzKbj1cYDY" + "2Ww8AMuOL7NTiBg6koZX2rruhFhjLJsVP5iv8bFTSBj6xxo/CHqxXftwYxFTKwhY/aj9iog" + "YOgfrRwCM/vr0qXOmpUQ0pXAVYYZa19tuymc8xqvY1u0nnOXCUQQZ6vnf/p5jiibpqgOYxq" + "cctwRwFUEmqrD/1VvMYWppjGrUE7/ghkAHRYhxy8QdG6x79u2DBbru/mLHuQgyr+H9HYatC" + "kvv2U3Hdmv9nSgCzKyW/MnBpW1HvSz9gRHsMUAiGe/1OA5A9XlX/TQv7pkmZtzB/Y1UNvBM" + "P2NIDOVTeJjpT49lJNOjXHHq/Mb7eRQe5pnavAm2W3jRt33Fjw2t8C3qG3z8AWvsOnFba6Y" + "bNZTCw9yYYsg2qkfabqpZPkPOhXc2ET2bk3FpAvDXSJBxbSsZ29O1fz2BwrtvVlzSNb60vX" + "5ruEJI4WVUxxoTISSp46hWJaA4MtSw2dlVRXlq5jy6H65hRzw+XasSUBwYOu2rC4YO/bmWM" + "0EesPRQsGnsZiGFy9AlVbmRzG9dQrMr1NSEE1OEs+uEoXbivUGW+EBrIGh3KYkUDuP7bu3J" + "PZ7mOKSsgFr4ggeRwmE87/FfW9Pqbb74vqgOg3Ay5XqGmpRe9+U7vsvL/0oybZRE9rIhU65" + "j6Az9tZL0ffn3jdtyadNdzEAaTiZVBhn6O9y+YBxAUw64fnR+hxoUVXg5qWJjqBzcFsbutY" + "rDwwBWHvr9rUrc5E+q2JjQExceYduHruQqBgAe3NhvLBhDrNiYyD79agXzTtXg98xs9CIvc" + "sXGRPzQc7F68R23NlxZQtk+pZEohnoyBuDuqI9P99Y244rhJPeLMyZQ90exJgyUU/dgfPEp" + "KYp5UeHak83fT2Tf0pXX8hMlKMj6Znu57HIMcwjmZmCcI15BVICvWfLK7ExmKnzbPH3fJ6I" + "V9NzZLG/LKo4Y49kmOHKUaAVB2T8h1pzGGMeLrrSVmX71iPUzaOafMyRk15Lios4EixONl0" + "hU2ErldW82O5rOORIVU8ELDZ8xDq2sPRsmUTHvm8LuyvjFr/+Kc30kKpbtt6OuC+OefSOlK" + "rYTHqf5MNVPsoLs/2QjGZj/oSB5FCSPguRRkDwKkkdB8ihIHgXJoyB5FCSPguRRkDzKf7Z6" + "NUd33kmjAAAAAElFTkSuQmCC"; settingnames = [ {name: 'resize', title: 'Resize flash to full-screen', tooltip: 'Resizes the toon so it fills the entire window', def: 1}, {name: 'noscale', title: ' Show outside-the-frame action', tooltip: 'Lets you see what\'s happening beyond the frames', def: 0}, // {name: 'showmenu', title: 'Enable right-click menu', tooltip: 'Enables the right-click context menu', def: 1}, {name: 'seekbar', title: 'Show seek bar', tooltip: 'Lets you fast forward and rewind', def: 1}, {name: 'frames', title: ' Show frame counter on seek bar', tooltip: 'Shows you exactly where you are', def: 1}, {name: 'hrwiki', title: 'Add HRWiki link', tooltip: 'Adds a link to the appropriate page on the Homestar Runner Wiki', def: 1}, {name: 'prevnext', title: 'Show previous/next buttons', tooltip: 'Lets you easily move through SBEmails, TGS, etc', def: 1}, {name: 'checknext', title: ' Check if next exists', tooltip: 'Doesn\'t add a "next" link on the latest SBEmail, etc', def: 0}, //{name: 'flipper', title: 'Turn everything upside-down', tooltip: 'Relive the mania of inverted April Fools Day Homestar Runner', def: 0}, {name: 'navbar', title: 'Plain HTML navbar', tooltip: 'Replaces the flash navbar with normal links... so you can open in tabs, etc', def: 0}, {name: 'randot', title: ' Include Big Toons in rando', tooltip: 'Limit the "rando" function to what you like to watch', def: 1}, {name: 'randosh', title: ' Include Shorts in rando', tooltip: 'Limit the "rando" function to what you like to watch', def: 1}, {name: 'randoho', title: ' Include Holiday toons in rando', tooltip: 'Limit the "rando" function to what you like to watch', def: 1}, {name: 'randop', title: ' Include Puppet Stuff in rando', tooltip: 'Limit the "rando" function to what you like to watch', def: 1}, {name: 'randoteh', title: ' Include Powered by The Cheat in rando', tooltip: 'Limit the "rando" function to what you like to watch', def: 1}, {name: 'randosb', title: ' Include Strong Bad Emails in rando', tooltip: 'Limit the "rando" function to what you like to watch', def: 1}, {name: 'randoam', title: ' Include Answering Machine in rando', tooltip: 'Limit the "rando" function to what you like to watch', def: 1}, {name: 'randotgs', title: ' Include Teen Girl Squad in rando', tooltip: 'Limit the "rando" function to what you like to watch', def: 1}, {name: 'subtitles', title: 'Show subtitles', tooltip: 'Shows subtitles or captions below the toon, if any are available', def: 0}, {name: 'captions', title: ' Show captions', tooltip: 'Include sound effects in the subtitles', def: 1}, {name: 'colours', title: ' Use colours', tooltip: 'Distinguish characters by colour effects (turn off if colourblind)', def: 1}, {name: 'testsubs', title: ' Test subtitles script', tooltip: 'Use this to test a subtitles script (copy/paste into a text box)', def: 0}, {name: 'updates', title: 'Check for updates', tooltip: 'Regularly check for updates to the All-in-one script', def: 1} ]; settings = {}; for (i = 0; i < settingnames.length; i++) settings[settingnames[i].name] = GM_getValue(settingnames[i].name, settingnames[i].def) != 0; settings['language'] = GM_getValue('language', 'en'); defaultxmlfile = escape('<?xml version="1.0" encoding="utf-8"?>\n<transcript xml:lang="en-us">\n<line start="" end="" speaker=""></line>\n</transcript>'); settings['testsubsdata'] = unescape(GM_getValue('testsubsdata', defaultxmlfile)); settings['names'] = GM_getValue('names', 0); extrasettings = []; addsettingsbox(); document.body.style.margin = "0px"; // find flash objects switch (whichsite) { case 0: // www.homestarrunner.com var objs = document.getElementsByTagName("EMBED"); if (objs && objs.length >= 2) { var flashmovie = objs[0]; var navbar = objs[1]; } else if (objs && objs.length >= 1) { var flashmovie = objs[0]; var navbar = false; } else { var flashmovie = false; var navbar = false; } if (!flashmovie) { objs = document.getElementsByTagName("OBJECT"); if (objs && objs.length >= 1) var flashmovie = objs[0]; } break; case 1: // podstar.homestarrunner.com var objs = document.getElementsByTagName("EMBED"); var flashmovie = false; if (objs && objs.length >= 1) var navbar = objs[0]; else var navbar = false; break; case 2: // videlectrix var objs = document.getElementsByTagName("EMBED"); var navbar = false; if (objs && objs.length >= 1) var flashmovie = objs[0]; else var flashmovie = false; settings.navbar = false; break; case 3: // mirror var objs = document.getElementsByTagName("EMBED"); var flashmovie = false; if (objs && objs.length >= 1) var flashmovie = objs[0]; if (!flashmovie) { objs = document.getElementsByTagName("OBJECT"); if (objs && objs.length >= 1) var flashmovie = objs[0]; } navbar = document.getElementById('navbar'); if (!navbar) settings.navbar = false; var flashcontainer = document.getElementById('flash'); if (flashcontainer) flashcontainer.style.width = "auto"; break; } if (flashmovie) { //expose Flash plugin-added methods flashmovie = flashmovie.wrappedJSObject; // confirm that this is really a flash file // and not (for example) the embedded background sound on SB's website if (flashmovie.nodeName.toLowerCase() == "object") { var src = flashmovie.getAttribute('src'); if (src) { if (src.substring(src.length - 4).toLowerCase() != ".swf") flashmovie = false; } else { a = flashmovie.getElementsByTagName('param').namedItem("movie"); if (!a || a.value.substring(a.value.length - 4).toLowerCase() != ".swf") flashmovie = false; } } else if (flashmovie.nodeName.toLowerCase() == "embed") { var src = flashmovie.getAttribute('src'); if (!src || src.substring(src.length - 4).toLowerCase() != ".swf") flashmovie = false; } } if (!flashmovie) settings.resize = settings.seekbar = settings.frames = settings.flipper = settings.noscale = settings.showmenu = settings.subtitles = false; if (settings.flipper) settings.seekbar = settings.subtitles = false; // globals var settingsbox; var seekbar; var isPercentage = false; var aspect = 1.0; var randolink; var randourls = []; var subtitleholder; var transcript = []; var nosubtitles = document.createComment(""); var currentsubtitles = nosubtitles; var characters = { "sfx": { "color": "#FFF", "sfx": true, "name": {"en": ""} } }; var transcriptErrors; var subtitleLoop = false; // used by wikilink, prevnext, flipper... put it out here. var filename = location.pathname.toLowerCase(); i = filename.lastIndexOf('/'); if (i >= 0) filename = filename.substr(i + 1); i = filename.lastIndexOf('.'); if (i >= 0) filename = filename.substr(0,i); // pull puppet stuff out of its background if ((settings.flipper || settings.seekbar || settings.subtitles) && flashmovie.src=="puppet_background.swf") { var flashvars = getFlashVars(); if (flashvars.videoName) replaceFlash(flashvars.videoName); } if (settings.navbar) replacenavbar(); if (settings.subtitles) setupSubtitles(); if (settings.seekbar) addFlashControls(flashmovie); if (settings.resize) resize(); if (settings.resize && settings.noscale) noscale(); //if (settings.showmenu) // showmenu(); if (settings.hrwiki) wikilink(); if (settings.prevnext) prevnext(); if (settings.flipper && whichsite == 0) flipper(); if (settings.updates) checkupdates(); // mess with popup windows - make them bigger and resizeable var oldopen = unsafeWindow.open; unsafeWindow.open = function(a,b,c) { c = c.split(/,/); var opts = {}; for (var i = 0; i < c.length; i++) { var d = c[i].split(/=/); if (d.length == 2) opts[d[0]] = d[1]; } opts["width"] = window.screen.width * 0.8; opts["height"] = window.screen.height * 0.8; opts["resizeable"] = "yes"; c = ""; for (var i in opts) { c += i + "=" + opts[i] + ","; } return oldopen(a,b,c); } } function replaceFlash(url) { where = flashmovie; while (where && where.parentNode && where.parentNode.nodeName.toLowerCase() == "object") where = where.parentNode; var newFlash=document.createElement("object"); newFlash.setAttribute("width",flashmovie.width); newFlash.setAttribute("height",flashmovie.height); newFlash.setAttribute("type","application/x-shockwave-flash"); newFlash.setAttribute("bgcolor",flashmovie.bgcolor ? flashmovie.bgcolor : "#FFFFFF"); newFlash.setAttribute("data",url); where.parentNode.replaceChild(newFlash,where); flashmovie=newFlash.wrappedJSObject; } function getSWFFilename() { // try to find the filename var a = flashmovie.src; if (!a) a = flashmovie.data; if (!a) { a = flashmovie.getElementsByTagName('param').namedItem('movie'); if (a) a = a.value; } return a; } function getFlashVars() { var flashvars = new Object(); var flashvarsstring = flashmovie.getAttribute("FlashVars"); if (!flashvarsstring) { flashvarsstring = flashmovie.getElementsByTagName('param').namedItem('FlashVars'); if (flashvarsstring) flashvarsstring = flashvarsstring.value; } // parse the string if (flashvarsstring) { var flashvarsparts = flashvarsstring.split('&'); for (var i = 0; i < flashvarsparts.length; i++) { var a = flashvarsparts[i].split('='); if (a.length == 2) flashvars[unescape(a[0])] = unescape(a[1]); } } var filename = getSWFFilename(); var i = filename.indexOf('?'); if (i >= 0) var flashvarsstring = filename.substring(i + 1); if (flashvarsstring) { var flashvarsparts = flashvarsstring.split('&'); for (var i = 0; i < flashvarsparts.length; i++) { var a = flashvarsparts[i].split('='); if (a.length == 2) flashvars[unescape(a[0])] = unescape(a[1]); } } return flashvars; } function addsettingsbox() { settingsbox = document.createElement('div'); settingsbox.style.borderRight = settingsbox.style.borderBottom = '1px solid #666'; settingsbox.style.background = '#EEE'; settingsbox.style.color = '#000'; settingsbox.style.position = 'fixed'; settingsbox.style.overflow = 'auto'; settingsbox.style.left = 0; settingsbox.style.top = 0; settingsbox.style.width = '350px'; settingsbox.style.font = '12px sans-serif'; settingsbox.style.textAlign = 'left'; settingsbox.style.display = 'none'; settingsbox.style.zIndex = 2; document.body.appendChild(settingsbox); var titlebar = document.createElement('div'); titlebar.style.fontWeight = "bolder"; titlebar.style.background = "#CCC"; titlebar.style.borderBottom = "1px solid #666"; titlebar.style.padding = '3px'; settingsbox.appendChild(titlebar); var closebutton = document.createElement('img'); closebutton.src = image_close; closebutton.title = "Click to hide preferences"; closebutton.style.cssFloat = "right"; closebutton.style.verticalAlign = "text-bottom"; closebutton.style.cursor = "pointer"; closebutton.style.display = "block"; closebutton.addEventListener('click', function(){settingsbox.style.display = "none"; settingslink.style.display = "block";}, false); titlebar.appendChild(closebutton); var prefslogo = document.createElement('img'); prefslogo.src = image_prefs; prefslogo.style.verticalAlign = "text-bottom"; titlebar.appendChild(prefslogo); titlebar.appendChild(document.createTextNode(" Preferences")); var settingsform = document.createElement('form'); settingsform.style.margin = 0; settingsform.style.padding = '3px'; settingsbox.appendChild(settingsform); var settingslist = document.createElement('ul'); settingslist.style.listStyle = "none"; var a = window.innerHeight - 75; if (a < 40) a = 40; settingslist.style.maxHeight = a + 'px'; settingslist.style.overflow = 'auto'; // vertical scrollbar if needed window.addEventListener('resize', function() { var a = window.innerHeight - 75; if (a < 40) a = 40; settingslist.style.maxHeight = a + 'px'; }, false); settingslist.style.padding = settingslist.style.margin = 0; settingsform.appendChild(settingslist); for (i = 0; i < settingnames.length; i++) { var settingrow = document.createElement('li'); settingnames[i].li = settingrow; var settingcheckbox = document.createElement('input'); settingcheckbox.type = "checkbox"; settingcheckbox.checked = settings[settingnames[i].name]; settingcheckbox.title = settingnames[i].tooltip; settingcheckbox.id = "setting_" + settingnames[i].name; settingcheckbox.addEventListener('click', enabledisable, false); settingrow.appendChild(settingcheckbox); settingnames[i].checkbox = settingcheckbox; var settinglabel = document.createElement('label'); settinglabel.htmlFor = "setting_" + settingnames[i].name; settinglabel.appendChild(document.createTextNode(' ' + settingnames[i].title)); settinglabel.title = settingnames[i].tooltip; settingrow.appendChild(settinglabel); settingnames[i].label = settinglabel; if (settingnames[i].title.charAt(0) == ' ') { // get number of spaces; var numspaces = 1; while (settingnames[i].title.charAt(numspaces) == ' ') numspaces++; var previousindex = i - 1; while (previousindex > 0 && settingnames[previousindex].title.substring(0, numspaces).match(/^ +$/)) previousindex--; if (previousindex >= 0) { settingnames[i].parent = settingnames[previousindex]; if (!settingnames[previousindex].ul) { settingnames[previousindex].ul = document.createElement('ul'); settingnames[previousindex].ul.style.listStyle = "none"; settingnames[previousindex].ul.style.padding = settingnames[previousindex].ul.style.margin = 0; settingnames[previousindex].ul.style.marginLeft = "2em"; settingnames[previousindex].li.appendChild(settingnames[previousindex].ul); } settingnames[previousindex].ul.appendChild(settingrow); } else settingslist.appendChild(settingrow); } else settingslist.appendChild(settingrow); } var div = document.createElement('div'); div.style.textAlign = "center"; settingsform.appendChild(div); var savebutton = document.createElement('input'); savebutton.type = "submit"; savebutton.value = "Save and Apply"; div.appendChild(savebutton); var nocachebutton = document.createElement('input'); nocachebutton.type = "submit"; nocachebutton.value = "Clear subtitles cache"; nocachebutton.addEventListener("click", function(){GM_setValue("cachedodge", Math.random().toString())}, false); div.appendChild(document.createTextNode(" ")); div.appendChild(nocachebutton); settingsform.addEventListener("submit", savesettings, false); var settingslink = document.createElement('div'); settingslink.style.borderRight = settingslink.style.borderBottom = '1px solid #666'; settingslink.style.background = '#EEE'; settingslink.style.display = "block"; settingslink.style.position = 'fixed'; settingslink.style.overflow = 'auto'; settingslink.style.left = '0px'; settingslink.style.top = '0px'; settingslink.style.padding = '3px'; settingslink.style.zIndex = 2; var settingslinkimage = document.createElement('img'); settingslinkimage.src = image_prefs; settingslinkimage.title = "Click to show preferences"; settingslinkimage.style.cursor = "pointer"; settingslinkimage.style.display = "block"; settingslinkimage.addEventListener('click', function(){settingsbox.style.display = "block"; settingslink.style.display = "none";}, false); settingslink.appendChild(settingslinkimage); document.body.appendChild(settingslink); // add some extra settings other than checkboxes that aren't handled in the structure above extrasettings[0] = {'name': 'language'}; var settingrow = document.createElement('li'); extrasettings[0].li = settingrow; var settinglabel = document.createElement('label'); settinglabel.htmlFor = "setting_language"; settinglabel.appendChild(document.createTextNode('Subtitle Language: ')); settinglabel.title = 'Display subtitles in this language, if any'; settingrow.appendChild(settinglabel); extrasettings[0].label = settinglabel; var settingselect = document.createElement('select'); settingselect.title = 'Display subtitles in this language, if any'; settingselect.id = "setting_language"; settingrow.appendChild(settingselect); extrasettings[0].select = settingselect; for (i = 0; i < settingnames.length; i++) { if (settingnames[i].name == "subtitles") { extrasettings[0].parent = settingnames[i]; settingnames[i].ul.insertBefore(settingrow, settingnames[i].ul.firstChild); } } extrasettings[0].populated = false; extrasettings[1] = {'name': 'testsubsdata'}; var div = document.createElement('div'); div.style.display = "block"; div.style.margin = "5px 10px 5px 2em"; div.style.textAlign = "center"; extrasettings[1].div = div; var settingtextarea = document.createElement('textarea'); settingtextarea.title = 'Paste your XML data here'; settingtextarea.id = "setting_testsubsdata"; settingtextarea.rows = 10; settingtextarea.style.width = "100%"; settingtextarea.style.fontSize = "10px"; settingtextarea.style.textAlign = "left"; settingtextarea.appendChild(document.createTextNode(settings['testsubsdata'])); div.appendChild(settingtextarea); extrasettings[1].textarea = settingtextarea; // only enable the refresh option if we're already set up for testing subtitles // - I'm not sure if it's robust otherwise. // // The interface for this thing is kinda confusing, so it's not in the script by default // change the "false" to a "true" to include it. if (settings.testsubs && false) { var settingbutton = document.createElement('input'); settingbutton.type = 'button'; settingbutton.title = 'Reload test XML data'; settingbutton.value = 'Reload Subtitles'; settingbutton.addEventListener('click', reloadSubtitles, false); div.appendChild(settingbutton); extrasettings[1].button = settingbutton; } for (i = 0; i < settingnames.length; i++) { if (settingnames[i].name == "testsubs") { extrasettings[1].parent = settingnames[i]; settingnames[i].li.appendChild(div); } } extrasettings[2] = {'name': 'names'}; var settingrow = document.createElement('li'); extrasettings[2].li = settingrow; var settinglabel = document.createElement('label'); settinglabel.htmlFor = "setting_names"; settinglabel.appendChild(document.createTextNode('Show speakers\' names: ')); settinglabel.title = 'Show the speakers\' names before their lines'; settingrow.appendChild(settinglabel); extrasettings[2].label = settinglabel; var settingselect = document.createElement('select'); settingselect.title = 'Show the speakers\' names before their lines'; settingselect.id = "setting_names"; settingrow.appendChild(settingselect); extrasettings[2].select = settingselect; var option = document.createElement('option'); option.value = "0"; option.appendChild(document.createTextNode("Never")); if (settings['names'] == 0) option.selected = true; settingselect.appendChild(option); var option = document.createElement('option'); option.value = "1"; option.appendChild(document.createTextNode("On voiceovers")); if (settings['names'] == 1) option.selected = true; settingselect.appendChild(option); var option = document.createElement('option'); option.value = "2"; option.appendChild(document.createTextNode("Always")); if (settings['names'] == 2) option.selected = true; settingselect.appendChild(option); for (i = 0; i < settingnames.length; i++) { if (settingnames[i].name == "colours") { extrasettings[2].parent = settingnames[i].parent; settingnames[i].parent.ul.insertBefore(settingrow, settingnames[i].li.nextSibling); } } enabledisable(); } function enabledisable() { for (i = 0; i < settingnames.length; i++) { if (!settingnames[i].parent) continue; enabled = true; p = settingnames[i].parent; while(p) { if (!p.checkbox.checked) { enabled = false; break; } p = p.parent; } settingnames[i].checkbox.disabled = !enabled; settingnames[i].label.style.color = enabled ? "inherit" : "#666"; } enabled = true; p = extrasettings[0].parent; while(p) { if (!p.checkbox.checked) { enabled = false; break; } p = p.parent; } extrasettings[0].select.disabled = !enabled; extrasettings[0].label.style.color = enabled ? "inherit" : "#666"; if (enabled && !extrasettings[0].populated) { var option = document.createElement('option'); option.appendChild(document.createTextNode("Loading...")); option.selected = true; extrasettings[0].select.appendChild(option); downloadxmlfromwiki("Subtitles:Languages", populatelanguagelist); } enabled = true; p = extrasettings[1].parent; while(p) { if (!p.checkbox.checked) { enabled = false; break; } p = p.parent; } extrasettings[1].textarea.disabled = !enabled; if (extrasettings[1].button) extrasettings[1].button.disabled = !enabled; // hide it entirely if immediate parent is disabled extrasettings[1].div.style.display = extrasettings[1].parent.checkbox.checked ? "block" : "none"; settingsbox.style.width = extrasettings[1].parent.checkbox.checked ? "500px" : "350px"; enabled = true; p = extrasettings[2].parent; while(p) { if (!p.checkbox.checked) { enabled = false; break; } p = p.parent; } extrasettings[2].select.disabled = !enabled; extrasettings[2].label.style.color = enabled ? "inherit" : "#666"; } function savesettings(e) { for (i = 0; i < settingnames.length; i++) { settingbox = settingnames[i].checkbox; if (settingbox) { settings[settingnames[i].name] = settingbox.checked; GM_setValue(settingnames[i].name, settingbox.checked ? 1 : 0); } } if (extrasettings[0].populated) { settings['language'] = extrasettings[0].select.value; GM_setValue('language', extrasettings[0].select.value); } settings['testsubsdata'] = extrasettings[1].textarea.value; GM_setValue('testsubsdata', escape(extrasettings[1].textarea.value)); // stop the form from actually being submitted if (e && e.preventDefault) { location.reload(); e.preventDefault(); } settings['names'] = extrasettings[2].select.value; GM_setValue('names', extrasettings[2].select.value); } // modified from Homestar-Fullon function doResize() { var dw = window.innerWidth; var dh = window.innerHeight - 15; // things get weird sometimes... -15 to make sure we don't get scrollbars. if (navbar) { // parseInt will take the number part at the start, turning eg "10px" into 10 a = document.defaultView.getComputedStyle(navbar, null); dh -= parseInt(a.height,10); dh -= parseInt(a.marginTop,10); dh -= parseInt(a.marginBottom,10); } if (seekbar) { a = document.defaultView.getComputedStyle(seekbar, null) dh -= parseInt(a.height,10); dh -= parseInt(a.marginTop,10); dh -= parseInt(a.marginBottom,10); } if (subtitleholder) { a = document.defaultView.getComputedStyle(subtitleholder, null) dh -= parseInt(a.height,10); dh -= parseInt(a.marginTop,10); dh -= parseInt(a.marginBottom,10); } if (transcriptErrors) { a = document.defaultView.getComputedStyle(transcriptErrors, null) dh -= parseInt(a.height,10); dh -= parseInt(a.marginTop,10); dh -= parseInt(a.marginBottom,10); } // enforce a (rather small) minimum size, regardless of how much crap is squeezed below the frame if (dw < 100) dw = 100; if (dh < 100) dh = 100; // if it was a percentage size, or we're looking outside the frame, just fill the whole window. // otherwise, keep the aspect ratio correct... "touch inside" style. if (!isPercentage && !settings.noscale) { if(dw/aspect <= dh) dh = Math.floor(dw / aspect); else dw = Math.floor(dh * aspect); } // set embed's size flashmovie.width = dw; flashmovie.height = dh; if (seekbar) seekbar.style.width = Math.max(dw, 450) + "px"; } function resize() { if (flashmovie.width.toString().indexOf('%') >= 0 || flashmovie.width.toString().indexOf('%') >= 0) isPercentage = true; else aspect = flashmovie.width/flashmovie.height; window.addEventListener('resize', doResize, false); doResize(); } // modified from the seek bar bookmarklet function addFlashControls(flash) { seekbar=document.createElement("div"); seekbar.style.width=Math.max(parseInt(flash.width)||0,450) + "px"; seekbar.style.margin = "0 auto"; var where=flash; while(where.parentNode.tagName.toLowerCase()=="object") where=where.parentNode; where.parentNode.insertBefore(seekbar,where.nextSibling); var table=document.createElement("table"); table.style.width="100%"; seekbar.appendChild(table); var row=table.insertRow(-1); var pauseButton=document.createElement("button"); pauseButton.appendChild(document.createTextNode("Pause")); var buttonCell=row.insertCell(-1); buttonCell.appendChild(pauseButton); var rewindCell=row.insertCell(-1); var rewindButton=document.createElement("button"); rewindButton.appendChild(document.createTextNode("<<")); rewindCell.appendChild(rewindButton); var prevCell=row.insertCell(-1); var prevButton=document.createElement("button"); prevButton.appendChild(document.createTextNode("|<")); prevCell.appendChild(prevButton); var slider=row.insertCell(-1); slider.width="100%"; var visibleSlider=document.createElement("div"); visibleSlider.style.position="relative"; visibleSlider.style.height="10px"; visibleSlider.style.width="100%"; visibleSlider.style.MozBorderRadius="4px"; visibleSlider.style.background="#333"; slider.appendChild(visibleSlider); var loadmeter=document.createElement("div"); loadmeter.style.position="absolute"; loadmeter.style.top=loadmeter.style.left = "0"; loadmeter.style.height="10px"; loadmeter.style.width="0px"; loadmeter.style.MozBorderRadius="4px"; loadmeter.style.background="#aaa"; visibleSlider.appendChild(loadmeter); var thumb=document.createElement("div"); thumb.style.position="absolute"; thumb.style.height="20px"; thumb.style.width="10px"; thumb.style.top="-5px"; thumb.style.MozBorderRadius="4px"; thumb.style.background="#666"; visibleSlider.appendChild(thumb); var nextCell=row.insertCell(-1); var nextButton=document.createElement("button"); nextButton.appendChild(document.createTextNode(">|")); nextCell.appendChild(nextButton); var ffCell=row.insertCell(-1); var ffButton=document.createElement("button"); ffButton.appendChild(document.createTextNode(">>")); ffCell.appendChild(ffButton); if (settings.frames) { var frameCell=row.insertCell(-1); var framecounter=document.createElement("div"); framecounter.style.background="#ccc"; framecounter.style.color="#000"; framecounter.style.fontWeight="bold"; framecounter.style.padding = "0 5px"; frameCell.appendChild(framecounter); framecountertext=document.createTextNode(""); framecounter.appendChild(framecountertext); } else framecountertext = false; if (!settings.noscale) { var zoomOutCell=row.insertCell(-1); var zoomOutButton=document.createElement("button"); // \u2212 is − zoomOutButton.appendChild(document.createTextNode("\u2212")); zoomOutCell.appendChild(zoomOutButton); var zoomNormalCell=row.insertCell(-1); var zoomNormalButton=document.createElement("button"); zoomNormalButton.appendChild(document.createTextNode("0")); zoomNormalCell.appendChild(zoomNormalButton); var zoomInCell=row.insertCell(-1); var zoomInButton=document.createElement("button"); zoomInButton.appendChild(document.createTextNode("+")); zoomInCell.appendChild(zoomInButton); } var sliderWidth; var paused=false; var dragging=false; var lastframe=-1; function pauseUnpause(){paused=flash.IsPlaying();pauseButton.style.borderStyle=paused?"inset":"";if(paused)flash.StopPlay();else flash.Play();} function rewind(){flash.GotoFrame(0); flash.Play();} function fastforward(){flash.GotoFrame(totalFrames() - 1);} function prevFrame(){flash.GotoFrame(flash.CurrentFrame()-1);} function nextFrame(){flash.GotoFrame(flash.CurrentFrame()+1);} function zoomIn(){flash.Zoom(67);} function zoomOut(){flash.Zoom(150);} function zoomNormal(){flash.Zoom(0);} pauseButton.addEventListener("click",pauseUnpause,false); rewindButton.addEventListener("click",rewind,false); prevButton.addEventListener("click",prevFrame,false); nextButton.addEventListener("click",nextFrame,false); ffButton.addEventListener("click",fastforward,false); if (!settings.noscale) { zoomOutButton.addEventListener("click",zoomOut,false); zoomNormalButton.addEventListener("click",zoomNormal,false); zoomInButton.addEventListener("click",zoomIn,false); } function update() { var fullSliderWidth=parseInt(getWidth(slider)); sliderWidth=parseInt(fullSliderWidth-getWidth(thumb)); var tot=totalFrames(); if (tot > 0) { var frame=flash.CurrentFrame(); if (frame < 0) frame = 0; if (framecountertext) { var a = tot.toString(); var b = (frame+1).toString(); while (b.length < a.length) b = "\u2007" + b; // U+2007 FIGURE SPACE framecountertext.nodeValue=b+"/"+a; } if(!dragging) { if (tot > 1) thumb.style.left=(frame/(tot - 1)*sliderWidth)+"px"; else thumb.style.left="0px"; paused=!flash.IsPlaying(); pauseButton.style.borderStyle=paused?"inset":""; } frame=flash.TGetProperty('/', 12); // property 12 is _framesloaded loadmeter.style.width=(frame/tot*fullSliderWidth)+"px"; } else if (framecountertext) { framecountertext.nodeValue="Loading..."; } } window.setInterval(update,50); function dragMousemove(e) { if (!dragging) return; var pageX=e.clientX+document.body.scrollLeft; var pos=bounds(0,pageX-getX(slider)-5,sliderWidth); t = totalFrames(); if (t > 1) { var frame=bounds(0,Math.round((t - 1)*pos/sliderWidth),t - 1); flash.GotoFrame(frame); } thumb.style.left=pos+"px"; } function release(e) { if (!dragging) return; if(!paused) flash.Play(); dragging=false; } function drag(e) { dragging=true; dragMousemove(e); e.preventDefault(); return false; } function bounds(min,val,max){return Math.min(Math.max(min,val),max);} function totalFrames(){if(typeof flash.TotalFrames=="number")return flash.TotalFrames;else if(typeof flash.TotalFrames=="function" || typeof flash.TotalFrames=="object")return flash.TotalFrames();else return 1;} function getWidth(elem){if(document.defaultView&&document.defaultView.getComputedStyle)return parseFloat(document.defaultView.getComputedStyle(elem,null).getPropertyValue("width"));else return parseFloat(elem.offsetWidth);} function getX(elem){if(!elem) return 0;return(elem.offsetLeft)+getX(elem.offsetParent);} slider.addEventListener("mousedown",drag,false); document.addEventListener("mousemove",dragMousemove,false); document.addEventListener("mouseup",release,false); } function noscale() { // have to wait until the Flash has loaded, otherwise SetVariable will fail. // best way I have found to test this, is if the current frame is >= 0... // before it's loaded, it's -1. // Before Flash itself initialises, CurrentFrame doesn't exist, so check for that too. var a = flashmovie.CurrentFrame; if (typeof(a) == "function" || typeof(a) == "object") a = flashmovie.CurrentFrame(); if (typeof(a) == "number" && a >= 0 && flashmovie.SetVariable) flashmovie.SetVariable("Stage.scaleMode", "noScale"); else setTimeout(noscale, 10); } function showmenu() { var a = flashmovie.CurrentFrame; if (typeof(a) == "function" || typeof(a) == "object") a = flashmovie.CurrentFrame(); if (typeof(a) == "number" && a >= 0 && flashmovie.SetVariable) flashmovie.SetVariable("Stage.showMenu", 1); else setTimeout(showmenu, 10); } function addHRWikiLink(pagename, isurl) { div = document.createElement("div") div.style.borderLeft = div.style.borderBottom = '1px solid #666'; div.style.background = '#EEE'; div.style.position = "fixed"; div.style.overflow = 'auto'; div.style.right = "0px"; div.style.top = "0px"; div.style.padding = "3px"; link = document.createElement("a"); if (isurl) link.href = pagename; else link.href = "http://www.hrwiki.org/wiki/" + escape(pagename.replace(/ /g, '_')); link.title = "See the HRWiki article for this page"; link.style.display = "block"; link.style.textDecoration = "none"; div.appendChild(link); img=document.createElement("img"); img.style.border="0px"; img.style.display="block"; img.src=image_hrwiki; link.appendChild(img); if (settings.subtitles) { link = document.createElement("a"); link.href = "http://www.hrwiki.org/wiki/Subtitles:" + escape(filename.replace(/ /g, '_')) + "/" + escape(settings.language); link.title = "See the HRWiki article for this page's subtitles"; link.style.display = "block"; link.style.textDecoration = "none" link.style.textAlign = "center"; link.style.fontSize = link.style.lineHeight = "16px"; link.style.marginTop = "3px"; div.appendChild(link); link.appendChild(document.createTextNode('S')); } document.body.appendChild(div); } function wikilink() { // many pages on the mirror have an "info" link in the navbar (thanks Tom!)... use that if (whichsite == 3) { var a = document.getElementById("navbar"); if (a) a = a.getElementsByTagName("a"); if (a) { for (i = 0; i < a.length; i++) { if (a[i].firstChild.nodeType == 3 && a[i].firstChild.nodeValue == "info") { addHRWikiLink(a[i].href, true); return; } } } } // pull the filename from the url, use it as a link to HRWiki // all the filenames except a couple of special-cases are // redirects to their articles // don't link to certain pages, they aren't redirects, but already existing pages // also detect a 404 error and special-case Strong Sad's Lament if (document.title == "Oops! You bwoke it.") addHRWikiLink("404'd"); else if (filename == "interview") addHRWikiLink("The_Interview"); else if (filename == "fhqwhgads") addHRWikiLink("Everybody_to_the_Limit"); else if (filename == "trogdor") addHRWikiLink("TROGDOR!"); else if (filename == "marshie") addHRWikiLink("Meet_Marshie"); else if (filename == "eggs") addHRWikiLink("Eggs_(toon)"); else if (filename == "fireworks") addHRWikiLink("Happy_Fireworks"); else if (filename == "sbemail100") addHRWikiLink("Not_the_100th_Email!!!"); else if (filename == "sbemail200") addHRWikiLink("Page_Load_Error"); else if (filename == "sbcg4ap") addHRWikiLink("Strong_Bad's_Cool_Game_for_Attractive_People_Advertisement"); else if (filename == "dangeresque") addHRWikiLink("Dangeresque_Roomisode_1:_Behind_the_Dangerdesque"); else if (location.pathname.substr(0, 12) == "/sadjournal/" && filename != "wonderyears" && filename != "super8") addHRWikiLink("Strong_Sad's_Lament"); else if (location.pathname.substr(0,5) == "/vii/" && (filename == "" || filename == "index")) addHRWikiLink("Viidelectrix"); else if (filename == "" || filename == "index") { if (whichsite == 0) addHRWikiLink("Index_Page"); else if (whichsite == 1) addHRWikiLink("Podstar_Runner"); else if (whichsite == 2) addHRWikiLink("Videlectrix"); else if (whichsite == 3) ; // this will be a 403 page - do nothing. } else addHRWikiLink(filename); } // Prev/Next links function addprevnextlinks(prefix,number) { if (number > 1) { var prevnum = (number - 1).toString(); var link = document.createElement("a"); if (prefix == "sbemail" && number == 101) link.href="sbemailahundred.html"; else if (prefix == "sbemail" && number == 152) link.href="kotpoptoon.html"; else if (prefix == "sbemail" && number == 201) link.href="sbemailtwohundred.html"; else if (prefix == "sbemail" && number == 202) link.href="hremail3184.html"; else link.href=prefix+prevnum+".html"; link.style.position="fixed"; link.style.left="0px"; link.style.bottom="0px"; link.style.padding="3px"; link.style.background="white"; link.style.border="1px solid black"; link.style.textDecoration="none"; link.appendChild(document.createTextNode('<')); document.body.appendChild(link); } var nextnum = (number + 1).toString(); var link = document.createElement("a"); if (prefix == "sbemail" && number == 99) link.href="sbemailahundred.html"; else if (prefix == "sbemail" && number == 150) link.href="kotpoptoon.html"; else if (prefix == "sbemail" && number == 199) link.href="sbemailtwohundred.html"; else if (prefix == "sbemail" && number == 200) link.href="hremail3184.html"; else link.href=prefix+nextnum+".html"; link.style.position="fixed"; link.style.right="0px"; link.style.bottom="0px"; link.style.padding="3px"; link.style.background="white"; link.style.border="1px solid black"; link.style.textDecoration="none"; link.appendChild(document.createTextNode('>')); if (settings['checknext']) { GM_xmlhttpRequest({ method: "HEAD", url: link.href + "?cachedodge=" + GM_getValue('cachedodge', 0), onload: function (results) { if (results.status == 200 && results.responseHeaders.indexOf("404error.html") < 0) document.body.appendChild(link); } }); } else document.body.appendChild(link); } function prevnext() { // this is coded like this instead of just looking for /(\d+)/ so that it // doesn't find pages like commandos3 or xmas04 var result; if ((result = filename.match(/^(sbemail|tgs|answer|bizcasfri|puppetjam|main)(\d+)$/))) { // sbemail100 and sbemail200 aren't actually sbemails if (!(result[1] == "sbemail" && (result[2] == "100" || result[2] == "200"))) addprevnextlinks(result[1],parseInt(result[2],10)); } else if (filename == "sbemailahundred") addprevnextlinks("sbemail", 100); else if (filename == "kotpoptoon") addprevnextlinks("sbemail", 151); else if (filename == "sbemailtwohundred") addprevnextlinks("sbemail", 200); else if (filename == "hremail3184") addprevnextlinks("sbemail", 201); else if (filename == "dween_tgs") addprevnextlinks("tgs", 6); } function flipper() { a = getSWFFilename(); if (!a) return; if (filename == "toons") replaceFlash("theyCallHimFlipperToons.swf?contentURL=" + escape(a)); else if (filename == "games") replaceFlash("theyCallHimFlipperGames.swf?contentURL=" + escape(a)); else if (filename == "payplus") replaceFlash("theyCallHimFlipperPayPlus.swf?contentURL=" + escape(a)); else if (filename == "main22") replaceFlash("theyCallHimFlipperVirusMain.swf?contentURL=" + escape(a)); else if (filename == "sbemail118") // virus *wasn't* flipped correctly originally, but I think having it work is better than // preserving the glitch. replaceFlash("theyCallHimFlipperVirusMain.swf?contentURL=" + escape(a)); else if (filename == "sbemailahundred") replaceFlash("theyCallHimFlipperHundred.swf?contentURL=" + escape(a)); else replaceFlash("theyCallHimFlipper.swf?contentURL=" + escape(a)); } function addnavbarlink(ul,href,title, extraclass) { var li = document.createElement("li"); var link = document.createElement("a"); link.href = href; link.appendChild(document.createTextNode(title)); if (extraclass) link.className = extraclass; li.appendChild(link); ul.appendChild(li); return link; } function replacenavbar() { // need to add the styles as a stylesheet, rather than inline styles // so that we can use :hover GM_addStyle( "#newnavbar { margin: 0; padding: 0; text-align: center; text-transform: lowercase; } " + "#newnavbar li { margin: 0; padding: 0; display: inline; } " + "#newnavbar :link, #newnavbar :visited { color: #666; font-family: sans-serif; text-decoration: none; padding: 0 1em; } " + "#newnavbar :link:hover, #newnavbar :visited:hover { color: #999; } " + // for overriding podstar's settings: "#newnavbar :link, #newnavbar :visited { font-weight: normal; } " + "#newnavbar :link:hover, #newnavbar :visited:hover { background: transparent; font-weight: normal; } " ); var newnavbar = document.createElement("ul"); newnavbar.id = "newnavbar"; newnavbar.style.height = newnavbar.style.fontSize = newnavbar.style.lineHeight = "10px"; if (!settings.seekbar) newnavbar.style.marginTop = "10px"; if (navbar) { var where = navbar; while(where.parentNode.tagName.toLowerCase() == "object") where = where.parentNode; where.parentNode.insertBefore(newnavbar, where); if (whichsite == 3) where.style.display = "none"; else where.parentNode.removeChild(where); } else document.body.appendChild(newnavbar); mainlink = addnavbarlink(newnavbar, "http://www.homestarrunner.com/main" + Math.floor(Math.random() * 25 + 1) + ".html", "Main"); // just for fun, re-randomise on each mouse-over (for the status bar) mainlink.addEventListener("mouseout",function(){mainlink.href="http://www.homestarrunner.com/main" + Math.floor(Math.random() * 25 + 1) + ".html"}, false); addnavbarlink(newnavbar, "http://www.homestarrunner.com/toons.html", "Toons"); addnavbarlink(newnavbar, "http://www.homestarrunner.com/games.html", "Games"); addnavbarlink(newnavbar, "http://www.homestarrunner.com/characters2.html", "Characters"); addnavbarlink(newnavbar, "http://www.homestarrunner.com/downloads.html", "Downloads"); addnavbarlink(newnavbar, "http://homestarrunner.stores.yahoo.net/", "Store", "storelink"); addnavbarlink(newnavbar, "http://www.homestarrunner.com/sbemail.html", "SB Emails"); addnavbarlink(newnavbar, "http://feeds.feedburner.com/HomestarRunner", "Subscribe"); addnavbarlink(newnavbar, "http://www.homestarrunner.com/email.html", "Contact"); //addnavbarlink(newnavbar, "http://podstar.homestarrunner.com/", "Podcast"); addnavbarlink(newnavbar, "http://www.homestarrunner.com/legal.html", "Legal"); randolink = addnavbarlink(newnavbar, "javascript:alert('rando.xml not loaded yet... be patient')", "Rando"); // load rando.xml and handle all that jazz GM_xmlhttpRequest({ method: "GET", url: "http://www.homestarrunner.com/rando.xml?cachedodge=" + GM_getValue('cachedodge', 0), onload: randoxml_loaded }); navbar = newnavbar; } function randoxml_loaded(results) { // info on DOMParser stole from http://www.webreference.com/programming/javascript/domwrapper/3.html var parser = new DOMParser(); // fix invalid XML... // add missing root element var doc = results.responseText.replace(/<\?xml.*?\?>/g, ""); // strip <?xml ?> tag doc = "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n<rando>" + doc + "</rando>"; // fix bad ampersands doc = doc.replace(/&(?!\w*;)/g, "&"); doc = parser.parseFromString(doc, "application/xml"); var sbemailcounter = 0; for (i = 0; i < doc.documentElement.childNodes.length; i++) { if (doc.documentElement.childNodes[i].nodeType == 1) { var type = doc.documentElement.childNodes[i].nodeName.toLowerCase(); if (settings['rando' + type] == false) // == false so that it's considered "true" for undefined... if they add a new toon type continue; var u = doc.documentElement.childNodes[i].getAttribute('u'); var n = doc.documentElement.childNodes[i].getAttribute('n'); if (!n) n = "Untitled"; if (type == "sb") { sbemailcounter++; n = "SBEmail: " + n; } if (u) randourls[randourls.length] = {u: "http://www.homestarrunner.com/" + u, n: n}; else randourls[randourls.length] = {u: "http://www.homestarrunner.com/sbemail" + sbemailcounter + ".html", n: n}; } } newrandolink() // just for fun, re-randomise on each mouse-over (for the status bar) randolink.addEventListener('mouseout', newrandolink, false); } function newrandolink() { if (randourls.length > 0) { var r = randourls[Math.floor(Math.random() * randourls.length)]; randolink.href = r.u; randolink.title = r.n; } else { randolink.href = "javascript:alert('Nothing to choose from')"; randolink.title = "Nothing to choose from"; } } function downloadxmlfromwiki(url, callback) { url = escape(url.replace(/ /g, '_')); GM_xmlhttpRequest({ method: "GET", url: "http://www.hrwiki.org/w/index.php?title=" + url + "&action=raw&cachedodge=" + GM_getValue('cachedodge', 0), onload: function(x) { xmldownloaded(x, callback, false, false); } }); } function xmldownloaded(results, callback, redirected, showerrors) { var text = results.responseText; // strip various things - templates and <pre> tags for wiki formatting, and <noinclude> sections... // <includeonly> tags are stripped (but their contents kept) for consistency. text = text.replace(/{{.*?}}/g, ""); text = text.replace(/<\/?pre[^>]*>/g, ""); text = text.replace(/<noinclude[^>]*>.*?<\/noinclude[^>]*>/g, ""); text = text.replace(/<includeonly[^>]*>(.*?)<\/includeonly[^>]*>/g, "$1"); text = text.replace(/^\s+/g, ""); // check for redirects var matches = text.match(/^#REDIRECT\s*\[\[(.*)\]\]/i); if (matches) { if (redirected) // trap double-redirects { removeSubtitles(); return; } text = matches[1]; if (matches = text.match(/^(.*)\|/)) text = matches[1]; if (matches = text.match(/^(.*)\#/)) text = matches[1]; text = text.replace(/^\s+|\s+$/g, ''); text = text.replace(/ /g, '_'); GM_xmlhttpRequest({ method: "GET", url: "http://www.hrwiki.org/w/index.php?title=" + escape(text) + "&action=raw&cachedodge=" + GM_getValue('cachedodge', 0), onload: function(x) { xmldownloaded(x, callback, true, showerrors); } }); return; } var parser = new DOMParser(); try { var doc = parser.parseFromString(text, "application/xml"); } catch (e) { if (showerrors) { transcriptError("Error in test subtitles:"); var pre = document.createElement("pre"); pre.style.font = "inherit"; pre.style.margin = "0.5em 0 0"; pre.appendChild(document.createTextNode(e.toString())) transcriptErrors.appendChild(pre); } removeSubtitles(); return; } // check if returned document is an error message if (doc.documentElement.lastChild && doc.documentElement.lastChild.nodeName == 'sourcetext') { // the xml document looks like // <parsererror>Error details<sourcetext>Source text</sourcetext></parsererror> if (showerrors) { transcriptError("Error in test subtitles:"); var pre = document.createElement("pre"); pre.style.font = "inherit"; pre.style.margin = "0.5em 0 0"; pre.appendChild(document.createTextNode(doc.documentElement.firstChild.nodeValue.replace(/Location: .*\n/, ""))) transcriptErrors.appendChild(pre); pre = document.createElement("pre"); pre.style.margin = "0.5em 0 0"; pre.appendChild(document.createTextNode(doc.documentElement.lastChild.firstChild.nodeValue)) transcriptErrors.appendChild(pre); } removeSubtitles(); return; } callback(doc); } function populatelanguagelist(xml) { while (extrasettings[0].select.firstChild) extrasettings[0].select.removeChild(extrasettings[0].select.firstChild); a = xml.getElementsByTagName('language'); for (i = 0; i < a.length; i++) { // sanity-check the node if (a[i].hasAttribute('xml:lang') && a[i].firstChild && (a[i].firstChild.nodeType == xml.TEXT_NODE || a[i].firstChild.nodeType == xml.CDATA_SECTION_NODE)) { var option = document.createElement('option'); option.appendChild(document.createTextNode(a[i].firstChild.nodeValue)); option.lang = option.value = a[i].getAttribute('xml:lang'); if (option.lang == settings['language']) option.selected = true; option.dir = "ltr"; if (a[i].hasAttribute('dir')) option.dir = a[i].getAttribute('dir'); extrasettings[0].select.appendChild(option); } } extrasettings[0].populated = true; } function setupSubtitles() { subtitleholder = document.createElement('div'); subtitleholder.style.color = "white"; subtitleholder.style.font = "20px/25px sans-serif"; subtitleholder.style.backgroundColor = "black"; subtitleholder.style.height = "100px"; //subtitleholder.style.marginTop = "10px"; subtitleholder.style.textAlign = "center"; where = flashmovie; while(where.parentNode.tagName.toLowerCase() == "object") where = where.parentNode; where.parentNode.insertBefore(subtitleholder, where.nextSibling); GM_addStyle( '.italic { font-style: italic; } ' + '.italic em, .italic cite, .italic i { font-style: normal; }' ); subtitleholder.appendChild(currentsubtitles = document.createTextNode("Loading subtitles...")); downloadxmlfromwiki('Subtitles:Characters', charactersLoaded); } function removeSubtitles() { if (subtitleholder) subtitleholder.parentNode.removeChild(subtitleholder); subtitleholder = false; if (settings.resize) doResize(); if (subtitleLoop) clearInterval(subtitleLoop); } function reloadSubtitles() { savesettings(false); if (!subtitleholder) { subtitleholder = document.createElement('div'); subtitleholder.style.color = "white"; subtitleholder.style.font = "20px/25px sans-serif"; subtitleholder.style.backgroundColor = "black"; subtitleholder.style.height = "100px"; //subtitleholder.style.marginTop = "10px"; subtitleholder.style.textAlign = "center"; where = flashmovie; while(where.parentNode.tagName.toLowerCase() == "object") where = where.parentNode; where.parentNode.insertBefore(subtitleholder, where.nextSibling); subtitleholder.appendChild(currentsubtitles = nosubtitles); } if (transcriptErrors) { transcriptErrors.parentNode.removeChild(transcriptErrors); transcriptErrors = false; } transcript = []; if (subtitleLoop) clearInterval(subtitleLoop); subtitleLoop = false; xmldownloaded({'responseText': settings.testsubsdata}, transcriptLoaded, false, true); } function charactersLoaded(doc) { var speakers = doc.getElementsByTagName("speaker"); for (var i = 0; i < speakers.length; i++) { var speakername = speakers[i].getAttribute("id"); characters[speakername] = {"color": speakers[i].getAttribute("color"), "sfx": speakers[i].hasAttribute("sfx"), "name": {"en": ""}}; var names = speakers[i].getElementsByTagName("name"); for (var j = 0; j < names.length; j++) { var lang = names[j].getAttribute("xml:lang"); if (names[j].firstChild && (names[j].firstChild.nodeType == doc.TEXT_NODE || names[j].firstChild.nodeType == doc.CDATA_SECTION_NODE)) characters[speakername].name[lang] = names[j].firstChild.nodeValue; } } if (!settings.testsubs) downloadxmlfromwiki('Subtitles:' + filename + '/' + settings.language, transcriptLoaded); else xmldownloaded({'responseText': settings.testsubsdata}, transcriptLoaded, false, true); } function transcriptLoaded(doc) { // set some defaults if (!doc.documentElement.getAttribute("xml:lang")) doc.documentElement.setAttribute("xml:lang", "en"); if (!doc.documentElement.getAttribute("dir")) doc.documentElement.setAttribute("dir", "ltr"); // inherit languages to all subnodes inheritLanguages(doc.documentElement); // now parse the lines into divs and get start and end frames var lines = doc.getElementsByTagName("line"); var previousEnd = NaN; for (var i = 0; i < lines.length; i++) { var line = new Object(); // ignore lines with missing start/end values // so you can add all the lines and not worry about timing them until later if (!lines[i].getAttribute("start") || !lines[i].getAttribute("end")) continue; line.start = parseInt(lines[i].getAttribute("start"), 10); line.end = parseInt(lines[i].getAttribute("end"), 10); if (settings.testsubs) { if (isNaN(line.start)) transcriptError("Start value \"" + lines[i].getAttribute("start") + "\" is not a number"); if (isNaN(line.end)) transcriptError("End value \"" + lines[i].getAttribute("end") + "\" is not a number"); if (line.end < line.start) transcriptError("Line beginning frame " + line.start + " ends before it begins."); if (line.start < previousEnd) transcriptError("Line beginning frame " + line.start + " starts before the previous frame ends."); previousEnd = line.end; } line.text = importNodes(lines[i]); transcript.push(line); } if (settings.resize) doResize(); subtitleLoop = setInterval(refreshSubtitles, 50); } function inheritLanguages(node) { for (var i = node.firstChild; i; i = i.nextSibling) { if (i.nodeType == i.ELEMENT_NODE) { if (!i.hasAttribute("xml:lang")) i.setAttribute("xml:lang", node.getAttribute("xml:lang")); if (!i.hasAttribute("dir")) i.setAttribute("dir", node.getAttribute("dir")); inheritLanguages(i); } } } // replacement for document.importNode() that actually works properly // turning eg <span> into an HTML span element, rather than an unknown element // that happens to be called "span". function importNodes(node) { var name = node.nodeName.toLowerCase(); if (characters[name]) { node.setAttribute("speaker", name); name = "speaker"; } if (name == "line" || name == "speaker") { // format the speaker appropriately as a div var speaker = node.getAttribute("speaker"); if (!settings.captions && (speaker == "sfx" || node.hasAttribute("sfx"))) return document.createComment(""); // return nothing newNode = document.createElement("div"); var char = characters[speaker]; if (!char) { if (settings.testsubs && speaker) { line = node; while (line && line.nodeName != "line") line = line.parentNode; if (line) transcriptError("Line beginning frame " + line.getAttribute("start") + " has an unrecognised speaker name \"" + speaker + '"'); } char = {"color": "#FFF", "name": {"en": ""}}; } if (settings.colours) newNode.style.color = char.color; if (node.hasAttribute("voiceover")) newNode.className = "italic"; if (node.hasAttribute("volume")) { newNode.style.fontSize = (node.getAttribute("volume") * 100) + "%"; newNode.style.lineHeight = "1.25em"; } newNode.lang = node.getAttribute("xml:lang"); newNode.dir = node.getAttribute("dir"); var hasSpeakerChildren = false; for (var i = node.firstChild; i; i = i.nextSibling) { if (i.nodeType == i.ELEMENT_NODE) { newNode.appendChild(importNodes(i)); var a = i.nodeName.toLowerCase(); if (i == "line" || i == "speaker" || characters[i]) hasSpeakerChildren = true; } else if (i.nodeType == i.TEXT_NODE || i.nodeType == i.CDATA_SECTION_NODE) newNode.appendChild(document.importNode(i, true)); } if (!hasSpeakerChildren) { // this is a normal text node - do some extra text stuff if (char.sfx || node.hasAttribute("sfx")) { newNode.insertBefore(document.createTextNode('('), newNode.firstChild); newNode.appendChild(document.createTextNode(')')) newNode.className = "italic"; } if (settings.names == 2 || (node.hasAttribute("voiceover") && settings.names == 1)) { // find the language with the longest prefix match // fall back to "en" if none found var bestmatch = "en"; var langbits = node.getAttribute("xml:lang").split("-"); for (i = langbits.length; i >= 1; i--) { var lang = langbits.slice(0, i).join("-"); if (char.name[lang]) { bestmatch = lang; break; } } if (char.name[bestmatch] != '') newNode.insertBefore(document.createTextNode(char.name[bestmatch] + ": "), newNode.firstChild); } } return newNode; } else { // check element blacklist if (name == "script" || name == "style" || name == "object" || name == "param" || name == "embed" || name == "a" || name == "img" || name == "applet" || name == "map" || name == "frame" || name == "iframe" || name == "meta" || name == "link" || name == "form" || name == "input") { if (settings.testsubs) transcriptError("Blacklisted element \"" + name + "\" stripped."); return document.createComment(""); // return nothing } var newNode = document.createElement(name); // copy across attributes for (var i = 0; i < node.attributes.length; i++) { name = node.attributes[i].nodeName.toLowerCase(); // check attribute blacklist // javascript, and anything that might load stuff from offsite if (name != "href" && name != "src" && name.substring(0, 2) != "on") { if (name == "style") { // regex taken from MediaWiki Sanitizer.php if (!node.attributes[i].nodeValue.match(/(expression|tps*:\/\/|url\\s*\()/i)) newNode.setAttribute("style", node.attributes[i].nodeValue); } else if (name == "xml:lang") { newNode.lang = node.attributes[i].nodeValue; } else newNode.setAttribute(node.attributes[i].nodeName, node.attributes[i].nodeValue); } else if (settings.testsubs) transcriptError("Blacklisted attribute \"" + name + "\" stripped."); } // copy across children for (var i = node.firstChild; i; i = i.nextSibling) { if (i.nodeType == i.ELEMENT_NODE) newNode.appendChild(importNodes(i)); else if (i.nodeType == i.TEXT_NODE || i.nodeType == i.CDATA_SECTION_NODE) newNode.appendChild(document.importNode(i, true)); } return newNode; } document.createComment(""); // fallthrough } function setSubtitles(node) { if (!node) node = nosubtitles; if (currentsubtitles != node) { subtitleholder.replaceChild(node, subtitleholder.firstChild); currentsubtitles = node; } } function refreshSubtitles() { var frame = false; if (!flashmovie) return; if (typeof(flashmovie.CurrentFrame) == "function" || typeof(flashmovie.CurrentFrame) == "object") frame = flashmovie.CurrentFrame(); if (typeof(frame) == "number" && frame >= 0) { // change from native 0-based to more friendly 1-based frame++; // binary search to find the right transcript line var first = 0; var last = transcript.length; while(first < (last - 1)) { var mid = (first + last) >> 1; if (frame >= transcript[mid].start) first = mid; else last = mid; } // should we actually show the line? if(transcript[first] && transcript[first].start <= frame && transcript[first].end >= frame) setSubtitles(transcript[first].text); else setSubtitles(false); } } function transcriptError(str) { if (!transcriptErrors) { transcriptErrors = document.createElement('div') transcriptErrors.style.color = "red"; transcriptErrors.style.background = "black"; transcriptErrors.style.font = "12pt sans-serif"; transcriptErrors.style.textAlign = "left"; transcriptErrors.style.margin = "0.5em"; document.body.appendChild(transcriptErrors); } else transcriptErrors.appendChild(document.createElement('br')); transcriptErrors.appendChild(document.createTextNode(str)); } function checkupdates() { var now = new Date().getTime(); var then = new Number(GM_getValue('lastchecktime', 0)); if (now - then > 86400000) // only check at most once per day { GM_xmlhttpRequest({ method: "GET", url: "http://www.hrwiki.org/wiki/Special:Getversion/User:Phlip/Greasemonkey?cachedodge=" + Math.random(), onload: function(r){GM_setValue('lastchecktime', ""+now);GM_setValue('lastcheckstring', r.responseText);return updatesstr_loaded(r.responseText);} }); } else updatesstr_loaded(GM_getValue('lastcheckstring', '')); } function updatesstr_loaded(str) { var parts = str.split("@@"); for (var i = 0; i < parts.length; i++) { var matches = parts[i].match(/^(\d+)\.(\d+)\.(\d+)=(.*)$/); if (!matches) continue; if (matches[1] > currentversion[0] || (matches[1] == currentversion[0] && matches[2] > currentversion[1]) || (matches[1] == currentversion[0] && matches[2] == currentversion[1] && matches[3] > currentversion[2])) { var updatelink = document.createElement('a'); updatelink.href=matches[4]; updatelink.style.display = "block"; updatelink.style.position = 'fixed'; updatelink.style.left = '0px'; updatelink.style.top = '0px'; updatelink.style.border = 'none'; updatelink.style.zIndex = 1; var updatelinkimage = document.createElement('img'); updatelinkimage.src = image_update; var oldversionstr = currentversion[0] + "." + currentversion[1] + "." + currentversion[2]; var newversionstr = matches[1] + "." + matches[2] + "." + matches[3]; updatelinkimage.title = "Click here to update from script version " + oldversionstr + " to " + newversionstr; updatelinkimage.style.display = "block"; updatelinkimage.style.border = 'none'; updatelink.appendChild(updatelinkimage); document.body.appendChild(updatelink); return; } } } //