AlkanFan

Untitled

May 8th, 2014
225
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.84 KB | None | 0 0
  1. // ==UserScript==
  2. // @name turkopticon
  3. // @version 2014.03.07
  4. // @description Review requesters on Amazon Mechanical Turk
  5. // @author Created by Lilly Irani and Six Silberman, modified by Miku
  6. // @license GNU GPL
  7. // @homepage http://turkopticon.ucsd.edu
  8. // @updateURL https://userscripts.org/scripts/source/166211.meta.js
  9. // @downloadURL https://userscripts.org/scripts/source/166211.user.js
  10. // @include https://*.mturk.com/mturk/viewhits*
  11. // @include https://*.mturk.com/mturk/findhits*
  12. // @include https://*.mturk.com/mturk/sorthits*
  13. // @include https://*.mturk.com/mturk/searchbar*
  14. // @include https://*.mturk.com/mturk/viewsearchbar*
  15. // @include https://*.mturk.com/mturk/sortsearchbar*
  16. // @include https://*.mturk.com/mturk/preview?*
  17. // @include https://*.mturk.com/mturk/statusdetail*
  18. // @include https://*.mturk.com/mturk/return*
  19. // @require https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js
  20. // @grant GM_xmlhttpRequest
  21. // ==/UserScript==
  22.  
  23. // Recent Changes
  24. // 2014-03-07 Added a backup server to keep Turkopticon online if the proxy server fails
  25. // 2014-02-28 Merged a fix from Six Silberman that handles blank values in the TO database
  26. // 2014-02-05 Fixed a bug that didn't display the blue box for requesters with no TO
  27. // 2014-02-04 Changed the pages in which the script is allowed to run which saves bandwidth - thank you mmmturkeybacon from mturkgrind
  28. // 2014-02-03 Added a patch for null values
  29. // 2014-01-28 Fixed the TO API by pointing it to the new server. Added in the new TOS violation count into the drop down.
  30. // 2013-05-02 Turkopticon data is now cached and refreshes every 30 minutes with the origin server.
  31. // 2013-05-01 Changed script processing to evaluate data after the page has loaded. Also fixed a bug where sometimes the JSON parsing failed.
  32. // 2013-04-30 Initial upload to userscripts
  33.  
  34. var TURKOPTICON_BASE = "http://turkopticon.ucsd.edu/";
  35. var TURKOPTICON_PROXY = "http://turkopticon.istrack.in/";
  36. var API_BASE = "http://turkopticon.ucsd.edu/api/";
  37. var API_PROXY_BASE = "https://api.turkopticon.istrack.in/";
  38. var API_PROXY_BACKUP = "https://api.differenceengines.com/";
  39. var API_MULTI_ATTRS_URL = API_PROXY_BASE + "multi-attrs.php?ids=";
  40.  
  41. function getRequesterAnchorsAndIds(a) {
  42. //a is a list of anchor DOM elements derived in the previous function
  43. var rai = {};
  44. var re = new RegExp(/requesterId/);
  45. var rf = new RegExp(/contact/);
  46. var isContactLink = new RegExp(/Contact/);
  47. var isImgButton = new RegExp(/img/);
  48. var requestersHere = false;
  49.  
  50. for (var i = 0; i < a.length; i++) {
  51. var href = a[i].getAttribute('href');
  52. if (re.test(href) /*&& !rf.test(href)*/ ) {
  53. var innards = a[i].innerHTML;
  54. if (!isContactLink.test(innards) && !isImgButton.test(innards)) {
  55. var id = a[i].href.split('requesterId=')[1].split('&')[0]
  56. if (!rai.hasOwnProperty(id)) {
  57. rai[id] = [];
  58. }
  59. rai[id].push(a[i]);
  60. requestersHere = true;
  61. }
  62. }
  63. }
  64.  
  65. rai = (requestersHere) ? rai : null;
  66. return rai;
  67. }
  68.  
  69. function buildXhrUrl(rai) {
  70. var url = API_MULTI_ATTRS_URL;
  71. var ri = Object.keys(rai);
  72. for (var i = 0; i < ri.length; i++) {
  73. url += ri[i];
  74. if (i < ri.length - 1) {
  75. url += ",";
  76. }
  77. }
  78. return url;
  79. }
  80.  
  81. function makeXhrQuery(url, reqAnchors) {
  82. GM_xmlhttpRequest({
  83. method: 'GET',
  84. timeout: 1000,
  85. url: url,
  86. onload: function (results) {
  87. //Test the http status code
  88. if (results.status != 200) {
  89. console.log("HTTP STATUS NOT OK, status: " + results.status);
  90. //Status is not OK, use the fallback
  91. useFallback(url, reqAnchors);
  92. } else {
  93. console.log("HTTP STATUS OK");
  94. /*r = results.responseText;
  95. console.log(r);*/
  96. var data = $.parseJSON(results.responseText);
  97. //console.log(data);
  98. getNamesForEmptyResponses(reqAnchors, data);
  99. insertDropDowns(reqAnchors, data);
  100. }
  101. },
  102. //Network level failure
  103. onerror: function () {
  104. console.log("NETWORK ERROR");
  105. useFallback(url, reqAnchors);
  106. },
  107. //Request timed out
  108. ontimeout: function (results) {
  109. console.log("REQUEST TIMEOUT");
  110. useFallback(url, reqAnchors);
  111. }
  112. });
  113. }
  114.  
  115. function useFallback(url, reqAnchors) {
  116. //If the TO proxy ever goes down, here we can switch to the backup
  117. return makeXhrQuery(url.replace(API_PROXY_BASE, API_PROXY_BACKUP), reqAnchors);
  118. }
  119.  
  120. function ul(cl, inner) {
  121. return "<ul class='" + cl + "'>" + inner + "</ul>";
  122. }
  123.  
  124. function li(cl, inner) {
  125. return "<li class='" + cl + "'>" + inner + "</li>";
  126. }
  127.  
  128. function span(cl, inner) {
  129. return "<span class='" + cl + "'>" + inner + "</span>";
  130. }
  131.  
  132. function strmul(str, num) {
  133. return Array(num + 1).join(str);
  134. }
  135.  
  136. function pad(word, space) {
  137. if (word.length >= space) {
  138. return word;
  139. } else {
  140. return word + strmul("&nbsp;", space - word.length);
  141. }
  142. }
  143.  
  144. function long_word(word) {
  145. switch (word) {
  146. case "comm":
  147. return "communicativity";
  148. break;
  149. case "pay":
  150. return "generosity";
  151. break;
  152. case "fair":
  153. return "fairness";
  154. break;
  155. case "fast":
  156. return "promptness";
  157. break;
  158. }
  159. }
  160.  
  161. function visualize(i, max, size) {
  162. var color;
  163. if (i / max <= 2 / 5) {
  164. color = 'red';
  165. } else if (i / max <= 3 / 5) {
  166. color = 'yellow';
  167. } else {
  168. color = 'green';
  169. }
  170. var filled = Math.round((i / max) * size);
  171. var unfilled = size - filled;
  172. var bar = span("bar", span(color, strmul("&nbsp;", filled)) + span("unf", strmul("&nbsp;", unfilled)));
  173. return bar;
  174. }
  175.  
  176. function attr_html(n, i) {
  177. return pad(long_word(n), 15) + ": " + visualize(i, 5, 30) + "&nbsp;" + i + " / 5";
  178. }
  179.  
  180. function ro_html(ro) {
  181. var rohtml = "";
  182. if (ro.attrs) {
  183. var keys = Object.keys(ro.attrs);
  184. if (ro.attrs[keys[0]]) {
  185. for (var i = 0; i < keys.length; i++) {
  186. rohtml += li("attr", attr_html(keys[i], ro.attrs[keys[i]]));
  187. }
  188. }
  189. }
  190. return rohtml;
  191. }
  192.  
  193. function what(ro) {
  194. var str = "";
  195. if (ro.attrs) {
  196. var keys = Object.keys(ro.attrs);
  197. if (ro.attrs[keys[0]]) {
  198. str = li("gray_link", "<a href='" + TURKOPTICON_BASE + "help#attr'>What do these scores mean?</a>");
  199. }
  200. }
  201. return str;
  202. }
  203.  
  204. function nrs(rid, nrevs) {
  205. var str = "";
  206. if (!nrevs) {
  207. str = "<li>No reviews for this requester</li>";
  208. } else {
  209. str = "<li>Scores based on <a href='" + TURKOPTICON_BASE + rid + "'>" + nrevs + " reviews</a></li>";
  210. }
  211. return str;
  212. }
  213.  
  214. function tos(tosflags) {
  215. if (!tosflags) {
  216. tosflags = 'N/A';
  217. }
  218. var str = "<li>Terms of Service violation flags: " + tosflags + "</li>";
  219. return str;
  220. }
  221.  
  222. function rl(rid, name) {
  223. var rl = "<li><a href='" + TURKOPTICON_BASE + "report?requester[amzn_id]=" + rid;
  224. rl += "&requester[amzn_name]=" + name + "'>";
  225. rl += "Report your experience with this requester &raquo;</a></li>";
  226. return rl;
  227. }
  228.  
  229. function dropDown(ro, rid) {
  230. var n = ro.name;
  231. var arrcls = "";
  232. if (ro.attrs) {
  233. var keys = Object.keys(ro.attrs);
  234. if (ro.attrs[keys[0]]) {
  235. arrcls = "toc";
  236. }
  237. }
  238. var dd = ul("tob", li(arrcls, "&#9660;") + ul("tom", ro_html(ro) + what(ro) + nrs(rid, ro.reviews) + tos(ro.tos_flags) + rl(rid, n)));
  239. return dd;
  240. }
  241.  
  242. function insertInlineCss() {
  243. var css = "<style type='text/css'>\n";
  244. css += ".tob, .tom { list-style-type: none; padding-left: 0; }\n";
  245. css += ".tob { float: left; margin-right: 5px; }\n";
  246. css += ".tob > .tom { display: none; position: absolute; background-color: #ebe5ff; border: 1px solid #aaa; padding: 5px; }\n";
  247. css += ".tob:hover > .tom { display: block; }\n";
  248. css += ".tob > li { border: 1px solid #9db9d1; background-color: #ebe5ff; color: #00c; padding: 3px 3px 1px 3px; }\n";
  249. css += ".tob > li.toc { color: #f33; }\n";
  250. css += "@media screen and (-webkit-min-device-pixel-ratio:0) { \n .tob { margin-top: -5px; } \n}\n"
  251. css += ".attr { font-family: Monaco, Courier, monospace; color: #333; }\n";
  252. css += ".bar { font-size: 0.6em; }\n";
  253. css += ".unf { background-color: #ddd; }\n";
  254. css += ".red { background-color: #f00; }\n";
  255. css += ".yellow { background-color: #f90; }\n";
  256. css += ".green { background-color: #6c6; }\n";
  257. css += ".gray_link { margin-bottom: 15px; }\n";
  258. css += ".gray_link a { color: #666; }\n";
  259. css += "</style>";
  260. var head = document.getElementsByTagName("head")[0];
  261. head.innerHTML = css + head.innerHTML;
  262. }
  263.  
  264. function getNamesForEmptyResponses(rai, resp) {
  265. for (var rid in rai) {
  266. if (rai.hasOwnProperty(rid)) {
  267. if (resp[rid] == "") { // empty response, no data in Turkopticon DB for this ID
  268. /**
  269. * Chrome + Firefox compatibility using jQuery
  270. */
  271. resp[rid] = $.parseJSON('{"name": "' + rai[rid][0].innerHTML + '"}');
  272. }
  273. resp[rid].name = rai[rid][0].innerHTML;
  274.  
  275. /*Firefox way which might not be compatible with chrome*/
  276. //resp[rid] = JSON.parse('{"name": "' + rai[rid][0].innerHTML + '"}');
  277. }
  278. } // overwrite name attribute of response object from page
  279. return resp;
  280. }
  281.  
  282. function insertDropDowns(rai, resp) {
  283. for (var rid in rai) {
  284. if (rai.hasOwnProperty(rid)) {
  285. for (var i = 0; i < rai[rid].length; i++) {
  286. var td = rai[rid][i].parentNode;
  287. td.innerHTML = dropDown(resp[rid], rid) + " " + td.innerHTML;
  288. }
  289. }
  290. }
  291. }
  292.  
  293. /**
  294. * Start execution script functions
  295. */
  296.  
  297. /**
  298. * Insert the CSS in the html head of the page
  299. */
  300. insertInlineCss();
  301.  
  302. /**
  303. * Gather all of the links on the page <a href="...">
  304. */
  305. var a = document.getElementsByTagName('a');
  306.  
  307. /**
  308. * Process the links to retrieve the requester data
  309. */
  310. var reqAnchors = getRequesterAnchorsAndIds(a);
  311.  
  312. /**
  313. * If the variable reqAnchors has data, lets review it
  314. */
  315. if (reqAnchors) {
  316.  
  317. /**
  318. * Build a list requester IDs separated by a comma
  319. */
  320. var url = buildXhrUrl(reqAnchors);
  321.  
  322. /**
  323. * Contact Turkopticon for data about all of the requesters in one http request
  324. */
  325. var turkopticon = makeXhrQuery(url, reqAnchors);
  326. }
Advertisement
Add Comment
Please, Sign In to add comment