- // ==UserScript==
- // @name Mturk Hourly
- // @author @Kerek
- // @description Record time spent working on HITs.
- // @match https://www.mturk.com/mturk/accept*
- // @match https://www.mturk.com/mturk/preview*
- // @match https://www.mturk.com/mturk/continue*
- // @match https://www.mturk.com/mturk/submit
- // @match https://www.mturk.com/mturk/return*
- // @match https://www.mturk.com/mturk/statusdetail*
- // @match https://www.mturk.com/mturk/dashboard
- // @require http://code.jquery.com/jquery-latest.min.js
- // @version 1.0
- // @grant none
- // @namespace https://greasyfork.org/users/11205
- // ==/UserScript==
-
- if (window.location.href == "https://www.mturk.com/mturk/dashboard" && $("#total_earnings_amount").length){
- Todays_Projected_Earnings();
- }
- else{
- var hit_returned = false;
- if(typeof(Storage)!=="undefined")
- {
- $('img[src="/images/return_hit.gif"]').parent().click(function(){
- hit_returned = true;
- });
- store_data('open');
- window.addEventListener('beforeunload', function(){store_data('close');});
-
- var $requesters = $('td[class="statusdetailRequesterColumnValue"]');
- if ($requesters.length > 0)
- {
- $requesters.each(function(){
- var hitId = $(this).find('a[href^="/mturk/contact?"]').attr('href').match(/[A-Z0-9]{30}/);
- var $feedback_value = $(this).parent().find('td[class="statusdetailStatusColumnValue"]').next();
- var feedback_str = create_feedback_str(hitId);
- var status_value = $feedback_value.html() + feedback_str;
- $feedback_value.html(status_value);
- });
- }
- }
- }
-
-
-
- function Todays_Projected_Earnings(){
- var TPEhitLOG = {}; var TPEdetailsLOG = {}; var TPEhourlyLOG = {}; var pe = 0;
-
- var today = $("a[href^='/mturk/statusdetail?encodedDate']:contains(Today)").eq(0).prop("href");
-
- var $peTR = $('<div id="TPE_div" class="even" style="display:table-row">');
- var $peTD1 = $('<td class="metrics-table-first-value">');
- var $peTD2 = $('<td>');
- var $peA = $('<a href="javascript:void(0)">Today\'s Projected Earnings</a>');
- var $TPE_details = $('<span style="color: blue; font-size: 10px; cursor: pointer; float: right;">Details<img style="margin-left: 5px;" src="/media/more.gif" border="0/"></span>');
- var $peSPAN = $('<span class="reward">$0.00</span>');
- $("td.metrics-table-first-value:contains(Total Earnings)").parent().after($peTR);
- $peTR.append($peTD1.append($peA,$TPE_details),$peTD2.append($peSPAN));
-
- var $TPED_table = $('<table style="display: none;" width="760" align="center" cellspacing="0" cellpadding="0">');
- var $TPED_tboday = $('<tbody>');
- var $TPED_tr_1 = $('<tr id="TPE_tr" height="25px"><td width="10" bgcolor="#7fb4cf" style="padding-left: 10px;"></td><td width="100%" bgcolor="#7fb4cf" class="white_text_14_bold">Today\'s Projected Earnings Details <a id="fourmEXPORT" href="javascript:void(0)" class="whatis" >(Forum Export)</a></td><td width="10" align="right" bgcolor="#7fb4cf"></td></tr>');
- var $TPED_tr_2 = $('<tr><td class="container-content" colspan="3"><table class="metrics-table" width="100%"><tbody><tr><td width="100%"><table class="metrics-table" width="100%"><tbody id="tbody2"></tbody></table></td></tr></tbody></table></td></tr>');
- var $TPED_tr_h = $('<tr class="metrics-table-header-row"><th class="metrics-table-first-header">Requester</th><th>Submitted</th><th>Projected</th><th>Hourly</th></tr>');
-
- $("#subtabs_and_searchbar").next().next().after($TPED_table);
- $TPED_table.append($TPED_tboday);
- $TPED_tboday.append($TPED_tr_1,$TPED_tr_2);
- $("#tbody2").append($TPED_tr_h);
-
- $("#fourmEXPORT").click(function(){
- var exportcode = "";
- var bonus = $("#bonus").text();
- if (bonus !== "$0.00"){
- var total = (Number(pe)+Number(bonus.replace(/[^0-9.]/g, ""))).toFixed(2);
- exportcode += "[b]Today's Projected Earnings: $"+Number(pe).toFixed(2)+" + Bonuses: "+bonus+" = $"+total+"[/b]\n";
-
- }
- else {
- exportcode += "[b]Today's Projected Earnings: $"+Number(pe).toFixed(2)+"[/b]\n";
- }
- exportcode += "[spoiler=Today's Projected Earnings Full Details][table][tr][th][b]Requester[/b][/th][th][b]Submitted[/b][/th][th][b]Projected[/b][/th][/tr]";
-
- var x_sorted = Object.keys(TPEdetailsLOG).sort(function(a,b){return TPEdetailsLOG[a].reward - TPEdetailsLOG[b].reward;});
- for (var j = x_sorted.length-1; j > -1; j--){
- var xkey = x_sorted[j];
- var x_req = TPEdetailsLOG[xkey].req;
- var x_reqid = TPEdetailsLOG[xkey].reqid;
- var x_submitted = TPEdetailsLOG[xkey].submit;
- var x_reward = Number(TPEdetailsLOG[xkey].reward).toFixed(2);
- if (x_req === "Bonuses"){
- if (x_reward !== "0.00"){
- exportcode += "[tr][td]"+x_req+"[/td][td]"+x_submitted+"[/td][td]$"+x_reward+"[/td][/tr]\n";
- }
- }
- else {
- exportcode += "[tr][td][url=https://www.mturk.com/mturk/searchbar?selectedSearchType=hitgroups&requesterId="+x_reqid+"]"+x_req+"[/url][/td][td]"+x_submitted+"[/td][td]$"+x_reward+"[/td][/tr]\n";
- }
- }
- exportcode += "[/table][/spoiler]";
-
- GM_setClipboard(exportcode);
- alert("Forum Export copied to your clipboard.");
- });
-
- $peA.click(function(){
- if ($peA.text() === "Today's Projected Earnings"){
- var confirmation = confirm("Are you sure you want to recalculate Today's Projected Earnings?");
- if (confirmation === true){
- TPEhitLOG = {}; TPEdetailsLOG = {}; TPEhourlyLOG = {}; pe = 0;
- $("#tbody2").find("tr.odd, tr.even").remove();
- getDATA(today);
- $peSPAN.text("$0.00");
- }
- }
- });
-
- $TPE_details.click(function(){
- $TPE_details.find("img").attr("src", ($TPE_details.find("img").attr("src") === "/media/more.gif") ? "/media/less.gif" : "/media/more.gif");
- $TPED_table.toggle();
- });
-
- if (today){
- var date = today.split("encodedDate=")[1];
- if (date === localStorage.TPE_date){
- if (localStorage.TPEhitLOG){
- TPEhitLOG = JSON.parse(localStorage.TPEhitLOG);
- }
- pe = Number(localStorage.TPE_pe) || 0;
- $peSPAN.text("$"+Number(pe).toFixed(2));
- getDATA(localStorage.TPE_lastpage);
- }
- else {
- localStorage.TPE_date = date;
- localStorage.Goal_progress = 0;
- TPEhitLOG = {}; pe = 0;
- $peSPAN.text("$0.00");
- getDATA(today);
- }
- }
-
- function getDATA(URL){
- var page = URL.match(/Number=([0-9]*)/g);
- if (page){
- $peA.text("Calculating Page "+page.toString().replace(/[^0-9.]/g, ""));
- }
- else {
- localStorage.removeItem("TPEhitLOG");
- localStorage.Goal_progress = 0;
- $peA.text("Calculating Page 1");
- }
-
- $.get(URL, function(data){
- var $data = $(data);
- var $hits = $data.find("#dailyActivityTable").find("tr[valign='top']");
- var pagereqerr = $data.find("td.error_title:contains(You have exceeded the maximum allowed page request rate for this website.)").length;
- var noactivity = $data.find("#dailyActivityTable").find("td:contains(You have no HIT activity on this day matching the selected status.)").length;
- if ($hits.length){
- console.log("hit length");
- var url = $data.find("a:contains(Next)").eq(0).prop("href");
- for (var i = 0; i < $hits.length; i++){
- var req = $hits.eq(i).find("td.statusdetailRequesterColumnValue").text().trim();
- var title = $hits.eq(i).find("td.statusdetailTitleColumnValue").text().trim();
- var reward = $hits.eq(i).find("td.statusdetailAmountColumnValue").text().trim();
- var status = $hits.eq(i).find("td.statusdetailStatusColumnValue").text().trim();
- var reqid = $hits.eq(i).find("a").prop("href").split("requesterId=")[1].split("&")[0];
- var hitid = $hits.eq(i).find("a").prop("href").split("HIT+")[1];
-
- if (!TPEhitLOG[hitid]){
- TPEhitLOG[hitid] = {
- req : req,
- title : title,
- reward : reward,
- status : status,
- reqid : reqid,
- hitid : hitid
- };
- }
- }
- if (url){
- getDATA(url);
- }
- else {
- pe = 0;
- for(var key in TPEhitLOG){
- if (TPEhitLOG[key].status !== "Rejected"){
- pe += parseFloat(TPEhitLOG[key].reward.replace(/[^0-9.]/g, ""));
- }
- if (!TPEdetailsLOG[TPEhitLOG[key].reqid]){
- TPEdetailsLOG[TPEhitLOG[key].reqid] = {
- req : TPEhitLOG[key].req,
- submit : 1,
- reward : parseFloat(TPEhitLOG[key].reward.replace(/[^0-9.]/g, "")),
- reqid : TPEhitLOG[key].reqid
- };
- }
- else {
- TPEdetailsLOG[TPEhitLOG[key].reqid].submit = TPEdetailsLOG[TPEhitLOG[key].reqid].submit + 1;
- TPEdetailsLOG[TPEhitLOG[key].reqid].reward = TPEdetailsLOG[TPEhitLOG[key].reqid].reward + parseFloat(TPEhitLOG[key].reward.replace(/[^0-9.]/g, ""));
- }
- if (!TPEhourlyLOG[TPEhitLOG[key].reqid]){
- var time_data = localStorage.getItem('time_data.' + TPEhitLOG[key].hitid.split('&')[0]);
- if (time_data != null){
- var starts = time_data.split("$#$")[3].split('?');
- var last_start = starts[starts.length-1];
-
- var stops = time_data.split("$#$")[4].split('?');
- var last_stop = stops[stops.length-1];
-
- if (last_start.length && last_stop.length){
- TPEhourlyLOG[TPEhitLOG[key].reqid] = {
- req : TPEhitLOG[key].req,
- intervals :[[last_start,last_stop]],
- totalReward : parseFloat(time_data.split("$#$")[2]),
- };
- }
-
- }
- }
- else{
- var time_data = localStorage.getItem('time_data.' + TPEhitLOG[key].hitid.split('&')[0]);
- if (time_data != null){
-
- var starts = time_data.split("$#$")[3].split('?');
- var last_start = starts[starts.length-1];
- var stops = time_data.split("$#$")[4].split('?');
- var last_stop = stops[stops.length-1];
- if (last_start.length && last_stop.length){
-
- //console.log(TPEhourlyLOG[TPEhitLOG[key].reqid].intervals);
- TPEhourlyLOG[TPEhitLOG[key].reqid].intervals.push([last_start,last_stop]);
- }
- // console.log(TPEhourlyLOG[TPEhitLOG[key].reqid].intervals);
- TPEhourlyLOG[TPEhitLOG[key].reqid].totalReward += parseFloat(time_data.split("$#$")[2]);
- }
- }
- }
-
- if (!TPEdetailsLOG.bonuses && $("#bonus").length){
- TPEdetailsLOG.bonuses = {
- req : "Bonuses",
- submit : "N/A",
- reward : parseFloat($("#bonus").text().replace(/[^0-9.]/g, "")),
- reqid : "N/A"
- };
- }
- else if ($("#bonus").length){
- TPEdetailsLOG.bonuses.reward = parseFloat($("#bonus").text().replace(/[^0-9.]/g, ""));
- }
-
- var d_sorted = Object.keys(TPEdetailsLOG).sort(function(a,b){return TPEdetailsLOG[a].reward - TPEdetailsLOG[b].reward;});
- var oddeven = true;
- for (var j = d_sorted.length-1; j > -1; j--){
- var dkey = d_sorted[j];
- var d_req = TPEdetailsLOG[dkey].req;
- var d_submitted = TPEdetailsLOG[dkey].submit;
- var d_reward = Number(TPEdetailsLOG[dkey].reward).toFixed(2);
- var d_hourly = "N/A";
- if (d_req !== "Bonuses" && TPEhourlyLOG[TPEdetailsLOG[dkey].reqid]){
- var intervals = TPEhourlyLOG[TPEdetailsLOG[dkey].reqid].intervals;
- var d_intervals_sum = 0;
- for (i=0;i<intervals.length;i++){
- d_intervals_sum += (intervals[i][1]-intervals[i][0]);
- }
- var d_intervals_avg = d_intervals_sum / intervals.length;
- var d_intervals = mergeIntervals(intervals);
- d_intervals = combineIntervals(intervals,Math.max(2*60*1000,Math.min(10*d_intervals_avg,15*60*1000)));
- console.log(d_req, "padding", Math.min(10*d_intervals_avg,15*60*1000));
- var d_time = 0;
- for (i=0;i<d_intervals.length; i++){
- var s = new Date(parseInt(d_intervals[i][0]));
- var f = new Date(parseInt(d_intervals[i][1]));
- console.log(d_req, i, s.toLocaleTimeString(),f.toLocaleTimeString());
- d_time += (d_intervals[i][1] - d_intervals[i][0])/(1000*60*60);
- }
- d_hourly = "$" + (TPEhourlyLOG[TPEdetailsLOG[dkey].reqid].totalReward / d_time).toFixed(2);
- }
- if (oddeven){
- oddeven = false;
- $("#tbody2").append('<tr class="odd"><td class="metrics-table-first-value">'+d_req+'</td><td>'+d_submitted+'</td><td><span class="reward">$'+d_reward+'</span></td><td><span class="reward">'+d_hourly+'</span></tr>');
- }
- else {
- oddeven = true;
- $("#tbody2").append('<tr class="even"><td class="metrics-table-first-value">'+d_req+'</td><td>'+d_submitted+'</td><td><span class="reward">$'+d_reward+'</span><td><span class="reward">'+d_hourly+'</span></td></tr>');
- }
- }
- localStorage.TPEhitLOG = JSON.stringify(TPEhitLOG);
- localStorage.TPE_lastpage = URL;
- localStorage.TPE_pe = pe;
- $peA.text("Today's Projected Earnings");
- $peSPAN.text("$"+Number(pe).toFixed(2));
- $('#today_total').text("$"+(Number($('#bonus').text().replace('$','')) +Number($('#TPE_div span.reward').text().replace('$',''))).toFixed(2));
- document.title = $('#today_total').text();
- localStorage.Goal_percent = ((Number(localStorage.TPE_pe)/Number(localStorage.Goal_goal))*100);
- localStorage.Goal_progress = Number(pe)-Number(localStorage.Goal_goal);
- if ($("#goalDIV").length){
- $("#progress").width(Number(localStorage.Goal_percent)+"%");
- $("#progressper").text(Number(localStorage.Goal_progress).toFixed(2));
- }
- Unsynced();
- }
- }
- else if (noactivity){
- console.log("no activity");
- localStorage.TPE_lastpage = URL;
- localStorage.TPE_pe = 0;
- localStorage.Goal_progress = 0;
- $peA.text("Today's Projected Earnings");
- $peSPAN.text("$0.00");
- $('#today_total').text("$"+(Number($('#bonus').text().replace('$','')) +Number($('#TPE_div span.reward').text().replace('$',''))).toFixed(2));
-
- }
- else if (pagereqerr) {
- console.log("set timeout");
- setTimeout(function(){ getDATA(URL); }, 2000);
- }
- });
- }
-
- function Unsynced(){
- var hitscalced = Object.keys(TPEhitLOG).length;
- var submitted = Number($("a[href^='/mturk/statusdetail?encodedDate']:contains(Today)").eq(0).parent().next().text());
-
- if (hitscalced < submitted){
- $peSPAN.css({backgroundColor:"red"});
- }
- else {
- $peSPAN.css({backgroundColor:""});
- }
- }
- }
-
-
- function create_feedback_str(hitId)
- {
- var time_str = '';
- var time_data = localStorage.getItem('time_data.' + hitId);
- if (time_data === null)
- {
- return time_str;
- }
- var last_start = time_data.split("$#$")[3].split('?');
- last_start = new Date(parseInt(last_start[last_start.length - 1]));
- var last_finish = time_data.split("$#$")[4].split('?');
- last_finish = new Date(parseInt(last_finish[last_finish.length - 1]));
-
- console.log(time_data, last_start, last_finish, time_data.split("$#$")[3].split('?'), time_data.split("$#$")[4].split('?'));
- var reward = time_data.split("$#$")[2];
- var time_spent = last_finish - last_start;
- var h = Math.floor(time_spent/(1000*60*60));
- var m = Math.floor((time_spent - h*1000*60*60)/(1000*60));
- var s = Math.floor((time_spent - h*1000*60*60 - m*1000*60)/(1000));
- // return time_data;
- // return time_data.split("$#$")[0] + " - " + time_data.split("$#$")[1] + " - " + time_data.split("$#$")[2] + "<br>" +last_start*1000 + "<br>" + last_finish*1000;
- return "Opened: " + last_start.toLocaleTimeString() + "<br>Submitted: " + last_finish.toLocaleTimeString()+ "<br>Time: " + (h.length?pad(h,2) + ":":"") + pad(m,2) + ":" + pad(s,2) + "<br>Hourly: $" + (reward/((last_finish-last_start)/(60*60*1000))).toFixed(2) ;
-
- // return time_data.split("$#$")[0] + " - " + time_data.split("$#$")[1] + " - " + time_data.split("$#$")[2] + "<br>" + (new Date(last_start)).toTimeString() + "<br>" + (new Date(last_finish)).toTimeString();
- }
-
- function store_data(action_type)
- {
- var $isAccepted = $('input[type="hidden"][name="isAccepted"][value="true"]');
- if ($isAccepted.length > 0 && !hit_returned)
- {
- var hitReview_hitId = $('form[name="hitForm"][action="/mturk/hitReview"] input[name="hitId"]').val();
- console.log(hitReview_hitId);
- var hit_reward = $('form[name="hitForm"][action="/mturk/submit"] input[name="prevReward"]').val().replace('USD','');
- console.log(hit_reward);
- var requester_name = $('td.capsule_field_title:contains("Requester:"):eq(0)').next().text().trim();
- var hit_title = $('table:contains("Requester:"):eq(0) table:eq(0)').text().trim();
- var now_in_milliseconds = new Date().getTime();
- var open_list = "";
- var close_list = "";
- var stored_copy = localStorage.getItem('time_data.' + hitReview_hitId);
- if (stored_copy !== null){
- open_list = stored_copy.split('$#$')[3];
- close_list = stored_copy.split('$#$')[4];
- }
- if (action_type == "open"){
- open_list += "?" + now_in_milliseconds;
- }
- else{
- close_list += "?" + now_in_milliseconds;
- }
- var autoapprove_data = requester_name + "$#$" + hit_title + "$#$"+ hit_reward +"$#$" + open_list + "$#$" + close_list;
- console.log(autoapprove_data);
- localStorage.setItem('time_data.' + hitReview_hitId, autoapprove_data);
- }
- }
-
- function mergeIntervals(intervals) {
- // test if there are at least 2 intervals
- if(intervals.length <= 1)
- return intervals;
-
- var stack = [];
- var top = null;
-
- // sort the intervals based on their start values
- intervals = intervals.sort(function (startValue, endValue) {
- if (startValue[0] > endValue[0]) {
- return 1;
- }
- if (startValue[0] < endValue[0]) {
- return -1;
- }
- return 0;
- });
-
- // push the 1st interval into the stack
- stack.push(intervals[0]);
-
- // start from the next interval and merge if needed
- for (var i = 1; i < intervals.length; i++) {
- // get the top element
- top = stack[stack.length - 1];
-
- // if the current interval doesn't overlap with the
- // stack top element, push it to the stack
- if (top[1] < intervals[i][0]) {
- stack.push(intervals[i]);
- }
- // otherwise update the end value of the top element
- // if end of current interval is higher
- else if (top[1] < intervals[i][1])
- {
- top[1] = intervals[i][1];
- stack.pop();
- stack.push(top);
- }
- }
-
- return stack;
- }
-
- function combineIntervals(intervals, padding) {
- // test if there are at least 2 intervals
- if(intervals.length <= 1)
- return intervals;
-
- var stack = [];
- var top = null;
-
- // push the 1st interval into the stack
- stack.push(intervals[0]);
-
- // start from the next interval and merge if needed
- for (var i = 1; i < intervals.length; i++) {
- // get the top element
- top = stack[stack.length - 1];
-
- // if the current interval doesn't overlap with the
- // stack top element, push it to the stack
- if ((intervals[i][0]-top[1]) > padding) {
- // console.log("hi",(intervals[i][0]-top[1]) + padding);
- stack.push(intervals[i]);
- }
- // otherwise update the end value of the top element
- // if end of current interval is higher
- else if (top[1] < intervals[i][1])
- {
- top[1] = intervals[i][1];
- stack.pop();
- stack.push(top);
- }
- }
- //console.log("stack",stack);
- return stack;
- }
-
- function pad(n, width, z) {
- z = z || '0';
- n = n + '';
- return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n;
- }