MTurk Time Tracker

Manual time tracking for MTurk. Use with MTurk Status Page Chart.

  1. // ==UserScript==
  2. // @name MTurk Time Tracker
  3. // @namespace localhost
  4. // @author ThirdClassInternationalMasterTurker
  5. // @description Manual time tracking for MTurk. Use with MTurk Status Page Chart.
  6. // @include https://www.mturk.com/mturk/*
  7. // @exclude https://www.mturk.com/mturk/status*
  8. // @version 0.3.5
  9. // @grant none
  10. // ==/UserScript==
  11.  
  12. //
  13. // 2012-09-14 First public release by ThirdClassInternationalMasterTurker
  14. //
  15. // 2012-09-15 0.3 Added some HIT tracking.
  16. // Show number of hits, time, estimated reward and hourly rate for latest activity
  17. // and projected earnings and hourly rate for today.
  18. //
  19. // 2012-09-16 0.3.1 Bug fix
  20. // 0.3.2 Better use of caching
  21. //
  22. // 2012-09-19 0.3.3 exclude https://www.mturk.com/mturk/status*
  23. //
  24. // 2012-10-11 0.3.4 Bug fix in format_date() (Integer/String mixup)
  25. //
  26. // 2012-12-02 0.3.5: Added @downloadURL and @updateURL
  27. //
  28.  
  29. /* ------------------------------------------------------------------------- */
  30. TRACK_HITS = true;
  31. /* ------------------------------------------------------------------------- */
  32.  
  33. // Stolen from Today's Projected Earnings (http://userscripts.org/scripts/show/95331)
  34. function getHTTPObject()
  35. {
  36. if (typeof XMLHttpRequest != 'undefined')
  37. {
  38. return new XMLHttpRequest();
  39. }
  40. try
  41. {
  42. return new ActiveXObject("Msxml2.XMLHTTP");
  43. }
  44. catch (e)
  45. {
  46. try
  47. {
  48. return new ActiveXObject("Microsoft.XMLHTTP");
  49. }
  50. catch (e) {}
  51. }
  52. return false;
  53. }
  54.  
  55. // Stolen from Today's Projected Earnings (http://userscripts.org/scripts/show/95331)
  56. function process_page(link)
  57. {
  58. var page = getHTTPObject();
  59. page.open("GET", link, false);
  60. page.send(null);
  61. return parse_data(page.responseText);
  62. }
  63.  
  64. // Partly stolen from Today's Projected Earnings (http://userscripts.org/scripts/show/95331)
  65. function parse_data(page_text) {
  66. var sub_total = 0;
  67. var rejected_rewards = 0;
  68. var rejected = 0;
  69. var index = 0;
  70. var page_html = document.createElement('div');
  71. var data = { hits: 0, rewards: 0, rejected: 0, rejected_rewards: 0 };
  72. page_html.innerHTML = page_text;
  73.  
  74. var amounts = page_html.getElementsByClassName('statusdetailAmountColumnValue');
  75. var statuses = page_html.getElementsByClassName('statusdetailStatusColumnValue');
  76.  
  77. for(var k = 0; k < amounts.length; k++)
  78. {
  79. if(statuses[k].innerHTML == 'Rejected') {
  80. data.rejected += 1;
  81. index = amounts[k].innerHTML.indexOf('$');
  82. data.rejected_rewards += parseFloat(amounts[k].innerHTML.substring(index+1));
  83. }
  84. else {
  85. index = amounts[k].innerHTML.indexOf('$');
  86. data.rewards += parseFloat(amounts[k].innerHTML.substring(index+1));
  87. }
  88. }
  89. data.hits = amounts.length;
  90. return data;
  91. }
  92.  
  93. // Gets status details for given date (MMDDYYYY)
  94. function getHITData(dataDate, cache) {
  95. var page;
  96. var data;
  97. var status = {hits:0,rewards:0, full_pages:0, full_page_rewards: 0, pages_fetched: 0, time: 0};
  98. if (typeof dataDate == 'undefined') dataDate = format_date(convert_timezone(new Date()));
  99. if (typeof cache == 'undefined') cache = true;
  100.  
  101. if (localStorage["STATUS " + dataDate]) {
  102. status = JSON.parse(localStorage["STATUS " + dataDate]);
  103. if (status.time && (status.time > convert_timezone(new Date()).getTime() - 43200000 )) {
  104. page = status.full_pages+1;
  105. status.hits = status.full_pages*25;
  106. status.rewards = status.full_page_rewards;
  107. status.pages_fetched = 0;
  108. }
  109. else {
  110. status = {hits:0,rewards:0, full_pages:0, full_page_rewards: 0, pages_fetched: 0, time: 0};
  111. }
  112. }
  113. else {
  114. page = 1;
  115. }
  116. for(page; page < 150; page++)
  117. {
  118. detailed_status_page_link = "https://www.mturk.com/mturk/statusdetail?sortType=All&pageNumber=" + page + "&encodedDate=" + dataDate;
  119. data = process_page(detailed_status_page_link);
  120. status.pages_fetched += 1;
  121.  
  122. if (data.hits == 0)
  123. break;
  124.  
  125. if (data.hits == 25) {
  126. status.full_pages += 1;
  127. status.full_page_rewards += data.rewards;
  128. }
  129. status.hits += data.hits;
  130. status.rewards += data.rewards;
  131. }
  132. status.time = convert_timezone(new Date()).getTime();
  133.  
  134. if (cache) {
  135. localStorage["STATUS " + dataDate] = JSON.stringify(status);
  136. }
  137. return status;
  138. }
  139.  
  140. function getHITDataFromCache(dataDate) {
  141. if (typeof dataDate == 'undefined') dataDate = format_date(convert_timezone(new Date()));
  142.  
  143. if (localStorage["STATUS " + dataDate])
  144. return JSON.parse(localStorage["STATUS " + dataDate]);
  145. return null;
  146. }
  147.  
  148. function formatTime(msec) {
  149. if (isNaN(msec))
  150. return "-";
  151. var seconds = Math.floor(msec / 1000) % 60;
  152. var minutes = Math.floor((msec / 1000) / 60) % 60;
  153. var hours = Math.floor(((msec / 1000) / 60) / 60) % 24;
  154.  
  155. if (hours > 0)
  156. seconds = "";
  157. else
  158. seconds = "" + seconds + "s";
  159. minutes == 0 ? minutes = "" : minutes = "" + minutes + "m ";
  160. hours == 0 ? hours = "" : hours = "" + hours + "h ";
  161.  
  162. return hours + minutes + seconds;
  163. }
  164.  
  165. function format_date(t) {
  166. var dateString = '';
  167. var tempMonth = t.getMonth()+1;
  168. var tempDate = t.getDate();
  169. if (tempMonth < 10) tempMonth = '0' + tempMonth;
  170. if (tempDate < 10) tempDate = '0' + tempDate;
  171. dateString = '' + tempMonth + tempDate + t.getFullYear();
  172. return dateString;
  173. }
  174.  
  175. // FIX!?
  176. function convert_timezone(t) {
  177. d = new Date();
  178. utc = d.getTime() + (d.getTimezoneOffset() * 60000);
  179.  
  180. // What is MTurk timezone. UTC-8??
  181. t_mturk = new Date(utc + (3600000*-8));
  182.  
  183. return t_mturk;
  184. }
  185.  
  186. function formatTime(msec) {
  187. if (isNaN(msec))
  188. return "-";
  189. var seconds = Math.floor(msec / 1000) % 60;
  190. var minutes = Math.floor((msec / 1000) / 60) % 60;
  191. var hours = Math.floor(((msec / 1000) / 60) / 60) % 24;
  192.  
  193. if (hours > 0)
  194. seconds = "";
  195. else
  196. seconds = "" + seconds + "s";
  197. minutes == 0 ? minutes = "" : minutes = "" + minutes + "m ";
  198. hours == 0 ? hours = "" : hours = "" + hours + "h ";
  199.  
  200. return hours + minutes + seconds;
  201. }
  202.  
  203. function worked_today() {
  204. var today = parseInt(localStorage[format_date(convert_timezone(new Date()))]);
  205. var status = getHITDataFromCache();
  206. if (isNaN(today))
  207. today = 0;
  208.  
  209. if (status == null)
  210. stat_line = "";
  211. else
  212. stat_line = " (~$" + status.rewards.toFixed(2) + " = $" + (status.rewards/(today/1000/60/60)).toFixed(2) + "/h)";
  213.  
  214. if (localStorage["LOG"] == "true") {
  215. today += (convert_timezone(new Date()).getTime()) - parseInt(localStorage["LOG START"]);
  216.  
  217. var time = time_worked();
  218. return formatTime(today) + stat_line + ") <br><span style=\"color: red\"> Working...</span> " + formatTime(time);
  219. }
  220.  
  221. return formatTime(today) + stat_line + "<br> " + localStorage["LATEST ACTIVITY"];
  222. }
  223. function time_worked() {
  224. if (localStorage["LOG"] && localStorage["LOG"] == "true") {
  225. var t = convert_timezone(new Date());
  226. start = new Date(parseInt(localStorage["LOG START"]));
  227. return (t.getTime()-start.getTime());
  228. }
  229. return 0;
  230. }
  231.  
  232. // FIX handle midnights...
  233. function toggle_logger() {
  234. var t = convert_timezone(new Date());
  235.  
  236. if (localStorage["LOG"] == "true") {
  237. localStorage["LOG"] = "false";
  238. start = new Date(parseInt(localStorage["LOG START"]));
  239. var today = parseInt(localStorage[format_date(t)]);
  240. if (isNaN(today))
  241. today = 0;
  242. var time_used = t.getTime()-start.getTime();
  243. localStorage[format_date(t)] = "" + (today + (t.getTime()-start.getTime()));
  244. this.style.color = 'green';
  245. this.textContent = 'Start';
  246.  
  247. if (TRACK_HITS) {
  248. var prev_status = getHITDataFromCache();
  249. var status = getHITData();
  250.  
  251. var hits_done = status.hits - prev_status.hits;
  252. var rewards = status.rewards - prev_status.rewards;
  253.  
  254. localStorage["LATEST ACTIVITY"] = "HITS: " + hits_done + " REWARD: $" + rewards.toFixed(2) +
  255. " TIME: " + formatTime(time_used) + " $" + (rewards/(time_used/1000/60/60)).toFixed(2) + "/h";
  256. }
  257. }
  258. else {
  259. localStorage["LOG"] = "true";
  260. localStorage["LOG START"] = t.getTime();
  261. this.style.color = 'red';
  262. this.textContent = 'Stop';
  263.  
  264. if (TRACK_HITS) {
  265. getHITData();
  266. }
  267. }
  268. };
  269.  
  270. if (true) {
  271. /* temporary fix */
  272. for (var i=0; i<7; i++)
  273. {
  274. if (localStorage["" + (2032+i)])
  275. {
  276. alert("MTurk Time Tracker fixing: " + "101" + i + "2012");
  277. localStorage["101" + i + "2012"] = localStorage["" + (2032+i)];
  278. delete localStorage["" + (2032+i)];
  279. }
  280. }
  281. /* ------------- */
  282.  
  283. var elements = document.getElementsByClassName('header_links');
  284. var newrow = document.createElement('tr');
  285. elements[0].parentNode.parentNode.parentNode.appendChild(newrow);
  286. newrow.innerHTML += "<td><button type=\"button\" id=\"toggle_logger\">X</button>" +
  287. "Worked today: <span id=\"worked_today\">" + worked_today() + "</span></td>";
  288. toggle_button = document.getElementById('toggle_logger');
  289. toggle_button.addEventListener("click", toggle_logger, false);
  290. localStorage["LOG"] == "true" ? toggle_button.style.color = 'red' : toggle_button.style.color = 'green';
  291. localStorage["LOG"] == "true" ? toggle_button.textContent = 'Stop' : toggle_button.textContent = 'Start';
  292.  
  293. worked = document.getElementById('worked_today');
  294. setInterval(function(){worked.innerHTML = worked_today();},1000);
  295. setInterval(function(){ localStorage["LOG"] == "true" ? toggle_button.style.color = 'red' : toggle_button.style.color = 'green';
  296. localStorage["LOG"] == "true" ? toggle_button.textContent = 'Stop' : toggle_button.textContent = 'Start';},5000);
  297. }
  298. else {
  299. //
  300. }