JR Mturk Panda Crazy Queue Helper

A script add on for Panda Crazy for displaying queue and sorting queue after submitting hits.

当前为 2016-09-23 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name        JR Mturk Panda Crazy Queue Helper
// @version     0.2.5
// @namespace   https://greasyfork.org/users/6406
// @description A script add on for Panda Crazy for displaying queue and sorting queue after submitting hits.
// @include     http*://*mturk.com/mturk/myhits*
// @include		http*://*mturk.com/mturk/findhits*
// @include		http*://*mturk.com/mturk/sorthits*
// @include		http*://*mturk.com/mturk/viewhits*
// @include     http*://*mturk.com/mturk/continue*
// @include     http*://*mturk.com/mturk/accept*
// @include     http*://*mturk.com/mturk/previewandaccept*
// @include     http*://*mturk.com/mturk/submit
// @include     http*://*mturk.com/mturk/return*
// @include		http*://*mturk.com/mturk/*searchbar*
// @include     http*://*mturk.com/mturk/return?requesterId=*
// @include     http*://*mturk.com/mturk/preview?prevRequester=*
// @exclude     http*://*mturk.com/mturk/findhits?*hit_scraper*
// @require     http://code.jquery.com/jquery-2.1.4.min.js
// @grant       GM_getValue
// @grant       GM_setValue
// ==/UserScript==

var gScriptVersion="0.2.5";
var gScriptName="pandacrazy";
var gLocation=window.location.href;
var gPandaCrazyLives=false, gHitExternalNextLink="", gHitExternalNextAcceptLink="";
var gPandaCrazyVersion=-1, gHitReturnLink="", gThisJob=null, gNoHits=false, gButtonSet=false;
var gQueueData=null, gPE=0, gTabTextMode=0, gTabTextTimer=0, gOriginalTitle=document.title, gCurrentPostion = 1;
var gSubmitHitID="", gReturnedHitID=""; // previous hitID submitted ore returned just to be sure it doesn't get redone.
var gCorrectVersion=false, gQueueSessOptions=null, gSubmitButton=null, gHitId=null, gIdNum=-1, gTabHitIds={};
var gThisTarget=(new Date().getTime()) + "_JRID"; // target ID from the time to distinguish different scripts and tabs.
var gThisId=-1; // ID number to represent the id in the Panda Crazy external data number ID just for separating messages.
var gQueueSessOptionsDef={"nextPosition":"--","nextIsLast":false,"nextIsSame":false,"tabNum":-1};
var gQueueLocalOptionsDef={"displayTabTitleQ":true,"displayTabTitleTime":true,"displayTabTitleName":true,"displayTabTitleToggle":false,"toggleTime":4000};
var jobDataDefault={"requesterName":"","requesterId":"","groupId":"","pay":"","title":"","duration":"0","hitsAvailable":0,"timeLeft":"","totalSeconds":0,"hitId":"",
		"continueURL":"","returnURL":"","durationParsed":null,"jobNumber":"-1","friendlyRName":"","friendlyTitle":"","assignedOn":"","description":"","qual":"","keywords":""};

function createDiv(theHtml) { var inner = (theHtml) ? theHtml : ""; return $('<div>').html(inner); }
function createSpan(theHtml) { var inner = (theHtml) ? theHtml : ""; return $('<span>').html(inner); }
function createButton(theText) { var inner = (theText) ? theText : ""; return $('<button>').html(inner); }
function createSelect(theId,theOptions) {
	var theSelect = $('<select>').attr({"id":theId});
	for (var i=0,len=theOptions.length; i<len; i++) { theSelect.append("<option value='" + theOptions[i] + "'>" + theOptions[i] + "</option>"); }
	return theSelect;
}
function createSelectNumbers(theId,first,min,max) { 
	var buildArray = [first];
	for (var i=min; i<=max; i++) { buildArray.push(i) }
	return createSelect(theId,buildArray);
}
function parseVersionString (str) {
    var x = str.split('.');
    var maj = parseInt(x[0]) || 0; var min = parseInt(x[1]) || 0; var pat = parseInt(x[2]) || 0;
    return {"major": maj, "minor": min, "patch": pat};
}
(function($){ $.fn.disableSelection = function() { return this.attr('unselectable', 'on').css('user-select', 'none').on('selectstart', false); }; })(jQuery);
function saveSessionData() {
	sessionStorage.setItem("JR_PC_QueueHelper",JSON.stringify(gQueueSessOptions));
}
function loadSessionData() {
	gQueueSessOptions = JSON.parse(sessionStorage.getItem('JR_PC_QueueHelper'));
	if (!gQueueSessOptions) {
		sessionStorage.setItem("JR_PC_QueueHelper",JSON.stringify(gQueueSessOptionsDef));
		gQueueSessOptions = JSON.parse(sessionStorage.getItem('JR_PC_QueueHelper'));
	}
}
function checkVersion(str) { 
	var versionObj = parseVersionString(str);
	if (versionObj.major>=0 && versionObj.minor>=3 && versionObj.patch>=7) return true;
	else return false;
}
function checkMode() {
	if (gLocation.indexOf("mturk/myhits") != -1) return "queuePageStart";
	else if (gLocation.indexOf("mturk/continue") != -1) return "hitPage";
	else if (gLocation.indexOf("mturk/accept") != -1 && gLocation.indexOf("&prevHitSubmitted=") != -1) return "accepted";
	else if (gLocation.indexOf("mturk/previewandaccept") != -1) return "accepted";
	else if (gLocation.indexOf("mturk/preview") != -1) return "previewPage";
	else if (gLocation.indexOf("mturk/submit") != -1) return "submitPage";
	else if (gLocation.indexOf("mturk/return") != -1) return "returnPage";
	return null;
}
function getTimeLeft(theTime) {
    if (theTime) {
        var tempArray = (theTime.indexOf("second") != -1) ? theTime.split("second")[0].trim().split(" ") : null;
		var seconds = (tempArray) ? tempArray[tempArray.length-1] : "0";
		tempArray = (theTime.indexOf("minute") != -1) ? theTime.split("minute")[0].trim().split(" ") : null;
		var minutes = (tempArray) ? tempArray[tempArray.length-1] : "0";
		tempArray = (theTime.indexOf("hour") != -1) ? theTime.split("hour")[0].trim().split(" ") : null;
		var hours = (tempArray) ? tempArray[tempArray.length-1] : "0";
		tempArray = (theTime.indexOf("day") != -1) ? theTime.split("day")[0].trim().split(" ") : null;
		var days = (tempArray) ? tempArray[tempArray.length-1] : "0";
		tempArray = (theTime.indexOf("week") != -1) ? theTime.split("week")[0].trim().split(" ") : null;
		var weeks = (tempArray) ? tempArray[tempArray.length-1] : "0";
		return( {"weeks":weeks,"days":days,"hours":hours,"minutes":minutes,"seconds":seconds} );
    } else return null;
}
function grabJobData() {
	var jobData = jQuery.extend(true, {}, jobDataDefault);
	var capsulelinkElement = $("form[name='hitForm'] .capsulelink_bold");
	var tableInfo = $(capsulelinkElement).closest("table").closest("table");
	jobData.groupId = (gLocation.indexOf("groupId=") != -1) ? gLocation.split("groupId=")[1].split("&")[0] : "";
	jobData.title = $(capsulelinkElement).find("div").text().trim();
	jobData.requesterId = ($("input[name='requesterId']:first").val()) ? $("input[name='requesterId']:first").attr("value") : "";
	jobData.requesterName = $("#requester\\.tooltip").closest("td").next().text().trim();
	jobData.duration = $("#time_left\\.tooltip").closest("td").next().text().trim();
	jobData.hitsAvailable = $("#number_of_hits\\.tooltip").closest("td").next().text().trim();
	jobData.pay = $("#reward\\.tooltip").closest("td").next().text().replace("$","").replace(" per HIT","").trim();
	return jobData;
}
function createMessageData(command,data,target,idNum,tabNum) { return {"time":(new Date().getTime()),"command":command,"data":data,"theTarget":target,"idNum":idNum,"tabNum":tabNum}; }
function sendCommandMessage(data) { localStorage.setItem("JR_message_" + gScriptName, JSON.stringify(data)); }

function sendMessageData(command,theData) {
	var messageData = createMessageData(command,theData);
	sendCommandMessage(messageData);
}
function sendPingMessage(target) { localStorage.setItem("JR_message_ping_" + gScriptName, JSON.stringify(createMessageData("areYouThere",null,target,null,null))); }
function sendPongMessage(target,idNum) { localStorage.setItem("JR_message_pong_" + gScriptName, JSON.stringify(createMessageData("iAmHere",null,target,idNum,null))); }
function sendQueuePageMessage(target,idNum) { localStorage.setItem("JR_message_" + gScriptName, JSON.stringify(createMessageData("getQueueData",null,target,idNum,null))); }
function sendSubmittedMessage(target,thisHitID,idNum) { localStorage.setItem("JR_message_" + gScriptName,
		JSON.stringify(createMessageData("submitted",{"hitId":thisHitID},target,idNum,null))); }
function sendAcceptedHitMessage(target,thisJobData,idNum) { localStorage.setItem("JR_message_" + gScriptName,
		JSON.stringify(createMessageData("acceptedhit",{"jobData":thisJobData},target,idNum,null))); }
function sendDoingHitMessage(tabNum,target,thisHitID,mode,idNum) { localStorage.setItem("JR_message_" + mode + "_" + tabNum + "_" + gScriptName,
		JSON.stringify(createMessageData("doinghit",{"hitId":thisHitID},target,idNum,tabNum))); }
function setSessionData() {
	if ($("#JRPCQAdvSel").length) gQueueSessOptions.nextPosition = $("#JRPCQAdvSel").val();
	if ($("#JRPCQEasySel").val()=="Last") gQueueSessOptions.nextIsLast = true; else gQueueSessOptions.nextIsLast = false;
	saveSessionData();
}
function setupOptionsMenu() {
	var insideContent = $("#JR_QueueOptionsMenu");
	createDiv("Queue Options Window").css({"font-size":"22px","text-align":"center","margin":"8px 0"}).appendTo(insideContent);
	var optionsArea = createDiv("").css({"font-size":"14px","text-align":"left","padding":"0 10px","margin-top":"20px"}).appendTo(insideContent);
	createDiv(createSpan("Go to the ").append(createSelect("JRPCQEasySel",["First","Last","--"])).append(createSpan(" hit in the queue."))).appendTo(optionsArea);
	createDiv(createSpan("Go to the next hit at position ").css({}).append(createSelectNumbers("JRPCQAdvSel","--",1,24)).append(createSpan(" in the queue."))).appendTo(optionsArea);
	createButton("OK").css({"margin-top":"40px","margin-left":"10px"}).click(function() { toggleOptionsMenu(); }).appendTo(optionsArea);
	$("#JRPCQEasySel").val((gQueueSessOptions.nextPosition!="--") ? "--" : ((gQueueSessOptions.nextIsLast) ? "Last" : "First"));
	$("#JRPCQAdvSel").val(gQueueSessOptions.nextPosition);
	$("#JRPCQEasySel").change(function() { 
		if ($(this).val()!="--") $("#JRPCQAdvSel").val("--"); else $("#JRPCQAdvSel").val("1");
		setSessionData();
	});
	$("#JRPCQAdvSel").change(function() { 
		if ($(this).val()!="--") $("#JRPCQEasySel").val("--"); else $("#JRPCQEasySel").val("First");
		setSessionData();
	});
}
function toggleOptionsMenu() {
	toggleOptionsMenu.display = toggleOptionsMenu.display || false;
	toggleOptionsMenu.display = !toggleOptionsMenu.display;
	if (toggleOptionsMenu.display) $("#JR_QueueOptionsMenu").show();	
	else $("#JR_QueueOptionsMenu").hide();
}
function inOtherTabs(hitId) {
	var foundIt=false;
	$.each(gTabHitIds, function(key,value) { if (value==hitId) foundIt=true; });
	return foundIt;
}
function firstOrLast(i) { return (gQueueSessOptions.nextIsLast) ? (i>0) : (i<gQueueData.length-1); }
function letsFindNext() {
}
function findNextHitQueue(currentHitID) {
	if (!gQueueData || currentHitID === "") return null;
	var i=-1, skip=false, targetHit=null, nextPosition = (gQueueSessOptions.nextPosition=="--") ? -2 : parseInt(gQueueSessOptions.nextPosition);
	var getLast = (gQueueSessOptions.nextIsLast) ? true : ((nextPosition>gQueueData.length-1) ? true : false);
	for (j=0,len=gQueueData.length;j<len;j++) {
		if (gQueueData[j].hitId==currentHitID) gCurrentPostion = j+1; // find the currenthit position
		if (!targetHit || getLast) { // if targethit not found or looking for last hit then keep on looking for target hit!
			if (gQueueData[j].hitId!=currentHitID && gQueueData[j].hitId!=gSubmitHitID && gQueueData[j].hitId!=gReturnedHitID && !inOtherTabs(gQueueData[j].hitId))
					targetHit = gQueueData[j];
			if (!getLast && nextPosition>0 && j<nextPosition) targetHit=null;
		}
	}
	if (!targetHit && gQueueData.length>1 && !getLast) targetHit = gQueueData[0];
	else if (!targetHit && gQueueData.length>1 && getLast) targetHit = gQueueData[gQueueData.length-1];
	return targetHit;
}
function findNextPositionQueue(position) {
}
function queuePageStart() {
	var sortresultsForm = $("#sortresults_form");
	var hitsText = $(sortresultsForm).prev();
	$(hitsText).find(".title_orange_text_bold").append(createSpan("PC Enhanced Mode").css({"font-size":"11px","padding":"1px 2px","background-color":"#FFE4C4","color":"black"}));
	var lastTables = $(sortresultsForm).next().next();
	var displayHits = $(sortresultsForm).next();
	var afterThis = $("#subtabs_and_searchbar");
	theMainContainer = createDiv().attr({"id":"JRMQContainer"}).insertAfter(afterThis);
	//createDiv().attr({"id":"JRNormalQueue"}).append(hitsText).append(displayHits).appendTo(theMainContainer);
	createDiv().attr({"id":"JRNormalQueue"}).appendTo(theMainContainer);
	$("#JRNormalQueue").append($(hitsText));
	$("#JRNormalQueue").append($(sortresultsForm));
	$("#JRNormalQueue").append($(displayHits));
	createDiv().attr({"id":"JREnhancedQueue1"}).appendTo(theMainContainer);
	createDiv().attr({"id":"JREnhancedQueue"}).appendTo(theMainContainer);
	gScriptMode = "queuePage";
}
function mainListener(e) {
	var returnedStorage = JSON.parse(e.newValue);
	if (!gPandaCrazyLives) {
		if ( e.key.substring(0,16) == 'JR_message_pong_' &&  e.key.substr(e.key.length - gScriptName.length) == gScriptName && // Receiving correct message from Panda Crazy
				returnedStorage && returnedStorage.theTarget == gThisTarget) { // Receiving as a targeted message for first message from Panda Crazy
			gPandaCrazyLives = true; // We now know Panda Crazy is running.
			gPandaCrazyVersion = returnedStorage.version;
			gIdNum = returnedStorage.idNum;
			gQueueSessOptions.tabNum = (gQueueSessOptions.tabNum!=-1) ? gQueueSessOptions.tabNum : gIdNum;
			saveSessionData();
			gCorrectVersion = checkVersion(gPandaCrazyVersion);
			if (gScriptMode=="queuePageStart" || gScriptMode=="hitPage" || gScriptMode=="previewPage") { sendQueuePageMessage(gThisTarget,gIdNum); }
		}
	} else if (gHitId!="" && e.key.substring(0,13) == "JR_message_D_") {
		var messageSender = returnedStorage.tabNum;
		if (messageSender && messageSender!=-1) delete gTabHitIds[messageSender];
	} else if (gHitId!="" && e.key.substring(0,13) == "JR_message_S_") {
		var messageSender = returnedStorage.tabNum;
		gTabHitIds[messageSender] = returnedStorage.data.hitId;
		sendDoingHitMessage(gQueueSessOptions.tabNum,gThisTarget,gHitId,"R",gIdNum);
	} else if (gHitId!="" && e.key.substring(0,13) == "JR_message_R_") {
		var messageSender = returnedStorage.tabNum;
		gTabHitIds[messageSender] = returnedStorage.data.hitId;
	} else if (gCorrectVersion && returnedStorage && returnedStorage.data) { // Panda Crazy is up and running with correct version.
		if (e.key.substring(0,11) == 'JR_message_' &&  e.key.substr(e.key.length - gScriptName.length) == gScriptName && // Receiving correct message from Panda Crazy
				(returnedStorage.theTarget == gThisTarget || returnedStorage.theTarget===null)) { // Receiving as a targeted message or a ping message
			if (returnedStorage.data.queue) gQueueData = returnedStorage.data.queue;
			if (returnedStorage.data.PE) gPE = returnedStorage.data.PE;
			if (returnedStorage.command=="ping") sendPongMessage(gThisTarget,gIdNum);
			if (gScriptMode=="queuePageStart") queuePageStart();
			else if (gSubmitButton.length && (gScriptMode=="hitPage" || gScriptMode=="previewPage")) { //console.log("This is a hitpage so looking for next target hit");
				if (!gButtonSet) {
					gButtonSet = true;
					createDiv("Q").css({"position":"fixed","width":"10px","text-align":"right","height":"20px","top":"22px","right":"2px","float":"right","padding":"0px 3px","background-color":"black","color":"white","opacity": "0.3","cursor":"pointer"}).disableSelection().click(function() { toggleOptionsMenu(); }).appendTo("body");
					createDiv("").css({"position":"fixed","width":"400px","height":"200px","top":"25px","right":"20px","float":"right","background-color":"#eceadf","border":"3px solid #000"}).attr({"id":"JR_QueueOptionsMenu"}).hide().appendTo("body");
					setupOptionsMenu();
					if (gHitId!="") sendDoingHitMessage(gQueueSessOptions.tabNum,gThisTarget,gHitId,"S",gIdNum);
				}
				targetHit = findNextHitQueue(gHitId);
				if (targetHit) {
					var realHitId = $("input[name='hitId']").eq(0).val();
					if (gHitExternalNextLink) $(gHitExternalNextLink).attr('href', targetHit.continueURL + "&prevsubmithitId=" + gHitId);
					if (gHitExternalNextAcceptLink) $(gHitExternalNextAcceptLink).attr('href', targetHit.continueURL + "&prevsubmithitId=" + gHitId);
					var theReturnLinkHref = "https://www.mturk.com/mturk/return?hitId=" + realHitId + "&hitNextId=" + targetHit.hitId + "&inPipeline=false";
					if (gHitReturnLink.length) $(gHitReturnLink).attr('href', theReturnLinkHref);
				} else {
					if (gHitExternalNextLink) {
                        var theNextLinkHref = $(gHitExternalNextLink).attr('href');
                        if (theNextLinkHref.indexOf("&prevsubmithitId=") == -1) theNextLinkHref = theNextLinkHref + "&prevsubmithitId=" + gHitId;
                        $(gHitExternalNextLink).attr('href', theNextLinkHref );
                    }
				}
				//console.log("Next link is now: " + $(gHitExternalNextLink).attr('href'));
			} else if (gScriptMode=="accepted" && gThisJob===null && !gNoHits) {
				gThisJob = grabJobData();
				sendAcceptedHitMessage(gThisTarget,gThisJob,idNum)
			}
		}
	}
}
loadSessionData();
gScriptMode = checkMode();
if (gLocation.indexOf("&prevsubmithitId=") != -1) { gSubmitHitID = (gLocation.split("&prevsubmithitId=")[1]).split("&")[0]; sendSubmittedMessage(gThisTarget,gSubmitHitID,gIdNum); }
if (gScriptMode=="returnPage") { 
	gReturnedHitID = (gLocation.indexOf("hitId=") != -1) ? (gLocation.split("hitId=")[1]).split("&")[0] : "";
	sendSubmittedMessage(gThisTarget,gReturnedHitID,gIdNum);
}
if (gScriptMode=="submitPage" || gScriptMode=="returnPage") {
	var goToNext = "";
	if (gLocation.indexOf("&hitNextId=") != -1) goToNext = "https://www.mturk.com/mturk/continue?hitId=" + (gLocation.split("&hitNextId=")[1]).split("&")[0];
	if (goToNext!=="") {
		$("body").html("");
		setTimeout(function() { window.location.replace(goToNext); },1100);
	}
}
if (gScriptMode) {
	window.addEventListener("storage", mainListener, false);
	gHitReturnLink = $("a[href*='mturk/return']");
	gNoHits = ($("#alertboxMessage").length) ? ( (($("#alertboxMessage").html()).indexOf("There are no HITs in this group available") != -1) ? true : false) : false;
	gSubmitButton = document.getElementsByName("/submit");
	if (gSubmitButton.length) {
		gHitExternalNextLink = $("#hitExternalNextLink");
		gHitExternalNextAcceptLink = $("#hitExternalNextAcceptLink");
		var hitIdNode = $("input[name='hitId']");
		gHitId = (hitIdNode.length>0) ? $("input[name='hitId']").eq(0).val() : "";
		setInterval( function() {
			var theTimer = $("#theTime").text();
			var theTimeLeftNode = $("a#time_left\\.tooltip");
			var theDuration = (theTimeLeftNode.length) ? theTimeLeftNode.parent().next().html().trim() : "";
			var requesterTip = $("#requester\\.tooltip");
			var requesterNameNode = (requesterTip.length) ? $(requesterTip).parent().next() : null;
			var theRequesterName = (requesterNameNode.length) ? $(requesterNameNode).text().trim() : "";
			gTabTextTimer+=1000;
			if (gTabTextTimer>=4000) {
				gTabTextTimer=0;
				gTabTextMode = 1 - gTabTextMode;
			}
			//if (gQueueData===null) document.title = "( " + theTimer + " of " + theDuration + " ) " + theRequesterName + " :: " + gOriginalTitle;
			if (gQueueData!==null) document.title = "( " + gCurrentPostion + "/" + gQueueData.length + " ) " + theRequesterName + " :: " + gOriginalTitle;
		},1000);
	}
	window.onbeforeunload = function() { sendDoingHitMessage(gQueueSessOptions.tabNum,gThisTarget,gHitId,"D",gIdNum); };
	sendPingMessage(gThisTarget);
}