Uncensor GameFAQs: G*** Edition

Uncensors "g***" formatted swears on GameFAQs.

  1. // ==UserScript==
  2. // @name Uncensor GameFAQs: G*** Edition
  3. // @namespace TheAmazingOne_VR@gamefaqs.com
  4. // @description Uncensors "g***" formatted swears on GameFAQs.
  5. // @include http://www.gamefaqs.com/boards/*
  6. // @version 1.61
  7.  
  8. //-------------------------------------------------------------------
  9. //
  10. // Uncensor GameFAQs
  11. //
  12. // Author: The Amazing One (the_amazing_one3000@yahoo.com)
  13. // Vague Rant (minor shit, no support, go away)
  14. //
  15. // Version 1.61 notes:
  16. // - Now implements some rudimentary all-caps guessing. It will
  17. // check the current word for capitals at either end of the
  18. // swear, e.g. ube[R]G*** will capitalize GRIS; otherwise it
  19. // will check the previous or next /two/ letters from adjacent
  20. // words, e.g. G*** [IT] or suc[K A] Gris. It's simpler than it
  21. // sounds. Just try it.
  22. // - Extremely inefficient! Really needs someone who actually
  23. // knows JavaScript and regex to take over!
  24. //
  25. //
  26. // Version 1.6 notes:
  27. // - G*** Edition means "Gris Edition". But "Gold" also fits. See,
  28. // it's clever. Bet you were all "Is that for 'Gris' or 'Gold'?"
  29. // - Updated to add support for new GameFAQs censorship rules
  30. // (first character no longer needs to be starred out). Covers a
  31. // few extra words over the old version, see the list below.
  32. // - I don't know either regex or JavaScript. This is a total hack
  33. // job. If anything doesn't work, it's because I hate you.
  34. //
  35. //
  36. // ----- About Uncensor GameFAQs -----
  37. // VR NOTE! RULES HAVE CHANGED SOME OF THIS IS WRONG BUT I'M
  38. // LAZY SO THE OLD DESCRIPTION IS STILL HERE. BRARUARBAURHAUH.
  39. //
  40. // Uncensor GameFAQs is a script that finds series of asterisks
  41. // on the GameFAQs message boards, and tries to figure out what
  42. // bad word the person meant. It makes its best guess, and fills
  43. // that word in. For convenience, it also replaces the bad words
  44. // in your own post with asterisks. Note that the Uncensor GameFAQs
  45. // script will always censor your own post with asterisks,
  46. // never by first letter. Therefore it is in your best interest
  47. // not to post something like "F is for fuck" since this will
  48. // be censored as "F is for ****", and that's a censor bypass. The
  49. // exception to this rule is the word "nigger", which is always
  50. // censored as "n-word" or "the n-word" (rather than six asterisks).
  51. //
  52. // Supported curse words:
  53. // - arsehole
  54. // - asshole
  55. // - bitch
  56. // - cunt
  57. // - fag
  58. // - fuck
  59. // - jizz
  60. // - nigger
  61. // - pussy
  62. // - pussies
  63. // - shit
  64. // - tits
  65. // - titties
  66. // - titty
  67. //
  68. // VR NOTE! Some of these words are really shitty to use as
  69. // descriptors for things, people, etc. Don't be a douchebag.
  70. //
  71. //-------------------------------------------------------------------
  72.  
  73.  
  74. // This script was initially adapted from IronicSans's "Uncensor the
  75. // Internet" script found at:
  76. // http://userscripts.org/scripts/show/8891
  77.  
  78. // ==/UserScript==
  79.  
  80. var badSp = [], goodSp = [];
  81. var bad = [], good = [];
  82. var badFlip = [], goodFlip = [];
  83.  
  84. var replacements = {
  85. "Da.\\*\\*\\*Wiz": "DaShizWiz",
  86.  
  87. "A\\*\\*\\*\\*\\*\\*\\*(?!\\*)": "Arsehole",
  88. "a\\*\\*\\*\\*\\*\\*\\*(?!\\*)": "arsehole",
  89. "A\\*\\*\\*\\*\\*\\*(?!\\*)": "Asshole",
  90. "a\\*\\*\\*\\*\\*\\*(?!\\*)": "asshole",
  91. "B\\*\\*\\*\\*(?!\\*)": "Bitch",
  92. "b\\*\\*\\*\\*(?!\\*)": "bitch",
  93. "C\\*\\*\\*(?!\\*)": "Cunt",
  94. "c\\*\\*\\*(?!\\*)": "cunt",
  95. "F\\*\\*(?!\\*)": "Fag",
  96. "f\\*\\*(?!\\*)": "fag",
  97. "F\\*\\*\\*(?!\\*)": "Fuck",
  98. "f\\*\\*\\*(?!\\*)": "fuck",
  99. "J\\*\\*\\*(?!\\*)": "Jizz",
  100. "j\\*\\*\\*(?!\\*)": "jizz",
  101. "N\\*\\*\\*\\*\\*(?!\\*)": "Nigger",
  102. "n\\*\\*\\*\\*\\*(?!\\*)": "nigger",
  103. "P\\*\\*\\*\\*(?!\\*)": "Pussy",
  104. "p\\*\\*\\*\\*(?!\\*)": "pussy",
  105. "P\\*\\*\\*\\*\\*\\*(?!\\*)": "Pussies",
  106. "p\\*\\*\\*\\*\\*\\*(?!\\*)": "pussies",
  107. "S\\*\\*\\*(?!\\*)": "Shit",
  108. "s\\*\\*\\*(?!\\*)": "shit",
  109. "T\\*\\*\\*(?!\\*)": "Tits",
  110. "t\\*\\*\\*(?!\\*)": "tits",
  111. "T\\*\\*\\*\\*\\*\\*(?!\\*)": "Titties",
  112. "t\\*\\*\\*\\*\\*\\*(?!\\*)": "titties",
  113. "T\\*\\*\\*\\*(?!\\*)": "Titty",
  114. "t\\*\\*\\*\\*(?!\\*)": "titty",
  115. "([A-Z] ?[A-Z] |[A-Z])Arsehole": "$1ARSEHOLE",
  116. "Arsehole(?=(?:([A-Z]| [A-Z])))": "ARSEHOLE",
  117. "([A-Z] ?[A-Z] |[A-Z])Asshole": "$1ASSHOLE",
  118. "Asshole(?=(?:([A-Z]| [A-Z])))": "ASSHOLE",
  119. "([A-Z] ?[A-Z] |[A-Z])Bitch": "$1BITCH",
  120. "Bitch(?=(?:([A-Z]| [A-Z])))": "BITCH",
  121. "([A-Z] ?[A-Z] |[A-Z])Cunt": "$1CUNT",
  122. "Cunt(?=(?:([A-Z]| [A-Z])))": "CUNT",
  123. "([A-Z] ?[A-Z] |[A-Z])Fag": "$1FAG",
  124. "Fag(?=(?:([A-Z]| [A-Z])))": "FAG",
  125. "([A-Z] ?[A-Z] |[A-Z])Fuck": "$1FUCK",
  126. "Fuck(?=(?:([A-Z]| [A-Z] ?[A-Z])))": "FUCK",
  127. "([A-Z] ?[A-Z] |[A-Z])Jizz": "$1JIZZ",
  128. "Jizz(?=(?:([A-Z]| [A-Z])))": "JIZZ",
  129. "([A-Z] ?[A-Z] |[A-Z])Nigger": "$1NIGGER",
  130. "Nigger(?=(?:([A-Z]| [A-Z])))": "NIGGER",
  131. "([A-Z] ?[A-Z] |[A-Z])Pussy": "$1PUSSY",
  132. "Pussy(?=(?:([A-Z]| [A-Z])))": "PUSSY",
  133. "([A-Z] ?[A-Z] |[A-Z])Pussies": "$1PUSSIES",
  134. "Pussies(?=(?:([A-Z]| [A-Z])))": "PUSSIES",
  135. "([A-Z] ?[A-Z] |[A-Z])Shit": "$1SHIT",
  136. "Shit(?=(?:([A-Z]| [A-Z])))": "SHIT",
  137. "([A-Z] ?[A-Z] |[A-Z])Tits": "$1TITS",
  138. "Tits(?=(?:([A-Z]| [A-Z])))": "TITS",
  139. "([A-Z] ?[A-Z] |[A-Z])Titties": "$1TITTIES",
  140. "Titties(?=(?:([A-Z]| [A-Z])))": "TITTIES",
  141. "([A-Z] ?[A-Z] |[A-Z])Titty": "$1TITTY",
  142. "Titty(?=(?:([A-Z]| [A-Z])))": "TITTY",
  143. "\\*\\*\\*\\*(?=(?:ING|ER)\\b)": "FUCK",
  144. "(^|\\n|\\t|[\\.!\\?] +)\\*\\*\\*\\*(?=(?:ing|er)\\b)": "$1Fuck",
  145. "([^\\*])\\*\\*\\*\\*(?=(?:ing|er)\\b)": "$1fuck",
  146. "THIS \\*\\*\\*\\*": "THIS SHIT",
  147. "This \\*\\*\\*\\*": "This shit",
  148. "this \\*\\*\\*\\*": "this shit",
  149. "(^|\\n|\\t|[^\\*])\\*\\*\\*\\*(?=(?:TY|TING| NO)\\b)": "$1SHIT",
  150. "(^|\\n|\\t|[\\.!\\?] +)\\*\\*\\*\\*(?=(?:ty|ting)\\b)": "$1Shit",
  151. "([^\\*])\\*\\*\\*\\*(?=(?:ty|ting)\\b)": "$1shit"
  152.  
  153. };
  154.  
  155. var specialReplacements = {
  156. "\\bthe n-word\\b": "\"nigger\"",
  157. "\\bn-word\\b": "nigger"
  158. };
  159.  
  160. var flipRules = {
  161. "fuck": "shit",
  162. "Fuck": "Shit",
  163. "FUCK": "SHIT",
  164. "shit": "fuck",
  165. "Shit": "Fuck",
  166. "SHIT": "FUCK",
  167. "bitch": "pussy",
  168. "Bitch": "Pussy",
  169. "BITCH": "PUSSY",
  170. "pussy": "bitch",
  171. "Pussy": "Bitch",
  172. "PUSSY": "BITCH"
  173. };
  174.  
  175. for (var key in specialReplacements) {
  176. badSp.push(new RegExp(key, "g"));
  177. goodSp.push(specialReplacements[key]);
  178. }
  179. for (var key in replacements) {
  180. bad.push(new RegExp(key, "g"));
  181. good.push(replacements[key]);
  182. }
  183. for (var key in flipRules) {
  184. badFlip.push(new RegExp(key));
  185. goodFlip.push(flipRules[key]);
  186. }
  187.  
  188. function doceval(q) {
  189. return document.evaluate(q, document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
  190. }
  191.  
  192. function uncensor(s,sp) {
  193. if(sp)
  194. for(var i=0; i<badSp.length; i++)
  195. s = s.replace(badSp[i],goodSp[i]);
  196. for(var i=0; i<bad.length; i++)
  197. s = s.replace(bad[i],good[i]);
  198. return s;
  199. }
  200.  
  201. function sanitize(s) {
  202. var flips = [], doubles = [];
  203. if(!s) return s;
  204. if(s.charAt(0)==" " && s.charAt(1)!=" ") {
  205. flips.push(0);
  206. doubles.push(false);
  207. }
  208. for(var p = s.indexOf(" ");p!=-1;p=s.indexOf(" ",p+1)) {
  209. if(s.charAt(p+2)==" ") continue;
  210. if(p+2==s.length) break;
  211. flips.push(p);
  212. var isDouble = (p==0||s.charAt(p-1)==" ");
  213. doubles.push(isDouble);
  214. if(p!=0) s = removeAt(s,p,(isDouble?2:1));
  215. }
  216. s = uncensor(s,false);
  217. for(var i=0; i<flips.length; i++)
  218. s = flipAt(s,flips[i],doubles[i]);
  219. s = uncensor(s,true);
  220. return s;
  221. }
  222.  
  223. function flipAt(s,i,dbl) {
  224. while(i<s.length && s.charAt(i)==" ")
  225. i++;
  226. if(i>=s.length) return s;
  227. var p = i;
  228. while(p<s.length && s.charAt(p)!=" ")
  229. p++;
  230. var sub = s.slice(i,p);
  231. sub = flipWord(sub);
  232. if(dbl) sub = flipWord(sub);
  233. s = removeAt(s,i,p-i);
  234. s = insertAt(s,sub,i);
  235. return s;
  236. }
  237.  
  238. function flipWord(s) {
  239. for(var i=0; i<badFlip.length; i++)
  240. if(badFlip[i].test(s)) {
  241. s=s.replace(badFlip[i],goodFlip[i]);
  242. return s;
  243. }
  244. return s;
  245. }
  246.  
  247. // replace in title
  248. if(document.title) {
  249. var gameFoxTitle = false;
  250. if(/^GameFAQs:M: /.test(document.title)) {
  251. gameFoxTitle = true;
  252. document.title = document.title.replace(/^GameFAQs:M: /,"");
  253. }
  254. document.title = sanitize(document.title);
  255. if(gameFoxTitle)
  256. document.title = "GameFAQs:M: "+document.title;
  257. }
  258. var h2s = doceval("//h2[@class='title']//text()");
  259. for(var i = 0; i < h2s.snapshotLength; i++) {
  260. node = h2s.snapshotItem(i);
  261. node.data = sanitize(node.data);
  262. }
  263. if(/post\.php/.test(window.location.href)) {
  264. var ttPreview = doceval("//div[@class='details']/p");
  265. if(ttPreview.snapshotLength>0) {
  266. node = ttPreview.snapshotItem(0);
  267. node.innerHTML = sanitize(node.innerHTML);
  268. }
  269. ttPreview = doceval("//div[@class='details']//a");
  270. if(ttPreview.snapshotLength>0) {
  271. node = ttPreview.snapshotItem(0);
  272. node.innerHTML = sanitize(node.innerHTML);
  273. }
  274. }
  275.  
  276. // replace in body text
  277. var gentopic = /\/boards\/[0-9]+-[^\/]*$|myposts|search/.test(window.location.href);
  278. var textnodes;
  279. if(gentopic)
  280. textnodes = doceval("//table[@class=\"board topics\"]//td//text()");
  281. else
  282. textnodes = doceval("//table[@class=\"board message\"]//td//text()");
  283. for (var i = 0; i < textnodes.snapshotLength; i++) {
  284. node = textnodes.snapshotItem(i);
  285. node.data = sanitize(node.data);
  286. }
  287.  
  288. function censor(text, sp) {
  289. if (sp) text =
  290. text.replace(/ARSEHOLE/g, "A*******").replace(/Arsehole/g, "A*******").replace(/arsehole/g, "a*******")
  291. .replace(/ASSHOLE/g, "A******").replace(/Asshole/g, "A******").replace(/asshole/g, "a******")
  292. .replace(/BITCH/g, "B****").replace(/Bitch/g, "B****").replace(/bitch/g, "b****")
  293. .replace(/CUNT/g, "C***").replace(/Cunt/g, "C***").replace(/cunt/g, "c***")
  294. .replace(/FAG/g, "F**").replace(/Fag/g, "F**").replace(/fag/g, "f**")
  295. .replace(/FUCK/g, "F***").replace(/Fuck/g, "F***").replace(/fuck/g, "f***")
  296. .replace(/JIZZ/g, "J***").replace(/Jizz/g, "J***").replace(/jizz/g, "j***")
  297. .replace(/NIGGER/g, "N*****").replace(/Nigger/g, "N*****").replace(/nigger/g, "n*****")
  298. .replace(/PUSSY/g, "P****").replace(/Pussy/g, "P****").replace(/pussy/g, "p****")
  299. .replace(/PUSSIES/g, "P******").replace(/Pussies/g, "P******").replace(/pussies/g, "p******")
  300. .replace(/SHIT/g, "S***").replace(/Shit/g, "S***").replace(/shit/g, "s***")
  301. .replace(/SHIZ/g, "S***").replace(/Shiz/g, "S***").replace(/shiz/g, "s***")
  302. .replace(/TITS/g, "T***").replace(/Tits/g, "T***").replace(/tits/g, "t***")
  303. .replace(/TITTIES/g, "T******").replace(/Titties/g, "T******").replace(/titties/g, "t******")
  304. .replace(/TITTY/g, "T****").replace(/Titty/g, "T****").replace(/titty/g, "t****");
  305. return text;
  306. }
  307.  
  308. function insertAt(string,sub,index) {
  309. return string.slice(0,index)+sub+string.slice(index);
  310. }
  311. function removeAt(string,index,count) {
  312. return string.slice(0,index)+string.slice(index+count);
  313. }
  314.  
  315. function prevWhitespace(string,index) {
  316. for(;index>0 && string.charAt(index-1)!="\n"
  317. && string.charAt(index-1)!="\t"
  318. && string.charAt(index-1)!=" "; index--);
  319. return index;
  320. }
  321.  
  322. function cleanUp(text) {
  323. var text2=text.toLowerCase();
  324. var text3=uncensor(censor(text,false)).toLowerCase();
  325. for(var p = text3.indexOf("fuck"); p!=-1; p = text3.indexOf("fuck",p+3)) {
  326. var p2 = prevWhitespace(text,p);
  327. if(text2.substr(p,4)=="shit") {
  328. text=insertAt(text," ",p2);
  329. text2=insertAt(text2," ",p2);
  330. text3=insertAt(text3," ",p2);
  331. }
  332. }
  333. for(var p = text3.indexOf("shit"); p!=-1; p = text3.indexOf("shit",p+3)) {
  334. var p2 = prevWhitespace(text,p);
  335. if(text2.substr(p,4)=="fuck") {
  336. text=insertAt(text," ",p2);
  337. text2=insertAt(text2," ",p2);
  338. text3=insertAt(text3," ",p2);
  339. }
  340. }
  341. for(var p = text3.indexOf("bitch"); p!=-1; p = text3.indexOf("bitch",p+3)) {
  342. var p2 = prevWhitespace(text,p);
  343. if(text2.substr(p,5)=="pussy") {
  344. text=insertAt(text," ",p2);
  345. text2=insertAt(text2," ",p2);
  346. text3=insertAt(text3," ",p2);
  347. }
  348. }
  349. for(var p = text3.indexOf("pussy"); p!=-1; p = text3.indexOf("pussy",p+3)) {
  350. var p2 = prevWhitespace(text,p);
  351. if(text2.substr(p,5)=="bitch") {
  352. text=insertAt(text," ",p2);
  353. text2=insertAt(text2," ",p2);
  354. text3=insertAt(text3," ",p2);
  355. }
  356. }
  357. return censor(text,true);
  358. }
  359.  
  360. function initRecensor() {
  361. var textareas = doceval("//div[@id=\"content\"]//textarea");
  362. if(textareas && textareas.snapshotLength>0) {
  363. var postBox = textareas.snapshotItem(0);
  364. var timedValidate = function(event) {
  365. setTimeout(validateFunction,10);
  366. };
  367. var validateFunction = function() {
  368. var selStart = postBox.selectionStart;
  369. var newText1 = cleanUp(postBox.value.substring(0,selStart));
  370. var newText2 = cleanUp(postBox.value.substring(selStart));
  371. if(newText1+newText2!=postBox.value) {
  372. postBox.value=newText1+newText2;
  373. postBox.setSelectionRange(newText1.length,newText1.length);
  374. }
  375. };
  376. var validateFunction2 = function(event) {
  377. postBox.value = cleanUp(postBox.value);
  378. }
  379. postBox.addEventListener("focus",timedValidate,true);
  380. postBox.addEventListener("blur",validateFunction2,true);
  381. return 0;
  382. } else
  383. setTimeout(initRecensor,1000); // GameFOX hasn't added the quickpost box yet
  384. }
  385.  
  386. function initRecensorTitle() {
  387. var topicTitle = doceval("//input[@name=\"topictitle\"]");
  388. if(topicTitle&&topicTitle.snapshotLength>0) {
  389. topicTitle = topicTitle.snapshotItem(0);
  390. var validateTitle = function(event) {
  391. topicTitle.value = cleanUp(topicTitle.value);
  392. }
  393. topicTitle.addEventListener("focus",validateTitle,true);
  394. topicTitle.addEventListener("blur",validateTitle,true);
  395. } else
  396. setTimeout(initRecensorTitle,1000);
  397. }
  398.  
  399. initRecensor();
  400. initRecensorTitle();
  401.  
  402.  
  403. // --------------------------------------------------------------------------
  404. // Check for updates
  405. //
  406. // Much thanks to Jarett - http://userscripts.org/users/38602 - for the code
  407. //---------------------------------------------------------------------------
  408. var version_scriptNum = 97311; // Change this to the number given to the script by userscripts.org (check the address bar)
  409. var version_timestamp = 1298091840552; // Used to differentiate one version of the script from an older one. Use the Date.getTime() function to get a value for this.
  410. function updateCheck(forced) {if((forced)||(parseInt(GM_getValue("lastUpdate", "0")) + 86400000 <= (new Date().getTime()))) {try {GM_xmlhttpRequest({method: "GET",url: "http://userscripts.org/scripts/review/" + version_scriptNum + "?" + new Date().getTime(),headers: {'Cache-Control': 'no-cache'},onload: function(xhrResponse) {GM_setValue("lastUpdate", new Date().getTime() + ""); var rt = xhrResponse.responseText.replace(/&nbsp;?/gm, " ").replace(/&#x000A;/g,"\n").replace(/<li>/gm, "\n").replace(/<[^>]*>/gm, ""); var scriptName = (/@name\s*(.*?)\s*$/m.exec(rt))[1]; GM_setValue("targetScriptName", scriptName); if (parseInt(/version_timestamp\s*=\s*([0-9]+)/.exec(rt)[1]) > version_timestamp) {if (confirm("There is an update available for the Greasemonkey script \"" + scriptName + ".\"\nWould you like to go to the install page now?")) {GM_openInTab("http://userscripts.org/scripts/show/" + version_scriptNum);}} else if (forced) {alert("No update is available for \"" + scriptName + ".\"");}}});} catch (err) {if (forced) {alert("An error occurred while checking for updates:\n" + err);}}}} GM_registerMenuCommand(GM_getValue("targetScriptName", "???") + " - Manual Update Check", function() {updateCheck(true);}); updateCheck(false);