IRC Export (reformatted output mod)

Export HIT information for IRC chat

As of 2015-02-13. See the latest version.

// ==UserScript==
// @name          IRC Export (reformatted output mod)
// @description   Export HIT information for IRC chat
// @version       3.4c
// @include       https://www.mturk.com/mturk/findhits*
// @include       https://www.mturk.com/mturk/viewhits*
// @include       https://www.mturk.com/mturk/sorthits*
// @include       https://www.mturk.com/mturk/searchbar*selectedSearchType=hitgroups*
// @include       https://www.mturk.com/mturk/viewsearchbar*selectedSearchType=hitgroups*
// @include       https://www.mturk.com/mturk/sortsearchbar*HITGroup*
// @include       https://www.mturk.com/mturk/preview*
// @grant         GM_setClipboard
// @author        Cristo + clickhappier
// @namespace     mturkgrind
// ==/UserScript==

// v3.0c notes:
// modified by clickhappier to reformat output in more logical ordering/separating/labeling,
//   since I thought it was unnecessarily unclear to read with the separators in the middle of each 
//   type of information (label, value, separator, relevant url) instead of between the different types,
//   and wanted to be clearer about what the TO values represented;
// also wanted to remove unnecessary linebreaks in the output that caused it to spread one HIT's info 
//   across several IRC comments, which made it hard to tell where one HIT's info stopped and another began
//   (though after the version I initially modified, Cristo did later do away with all but one linebreak);
// also fixed Amazon fiddling with HIT name cell contents after Oct 20, 2014 change;
// also fixed Turkopticon mirror API domain to keep working after Oct 27, 2014 change


var caps = document.getElementsByClassName('capsulelink');
for (var c = 0; c < caps.length/2; c++){
    button = document.createElement('button');
    button.setAttribute("place",c);
    button.textContent = 'IRC';
    button.style.height = '14px';
    button.style.width = '30px';
    button.style.fontSize = '8px';
    button.style.border = '1px solid';
    button.style.padding = '0px';
    button.style.backgroundColor = 'transparent';
    button.title = 'Click to save Hit information to your clipboard';
    button.addEventListener("click", display, false);
    document.getElementById('capsule'+c+'-0').parentNode.appendChild(button);
}

function getTO(f){
    var toComp = [];
    var toUrl = 'https://mturk-api.istrack.in/multi-attrs.php?ids='+f;
    requestTO = new XMLHttpRequest();
    requestTO.onreadystatechange = function () {
        if ((requestTO.readyState ===4) && (requestTO.status ===200)) {
            if(requestTO.responseText.split(':').length > 2){
                var toInfo = requestTO.responseText.split('{')[3].split('}')[0].split(',');
                for (var t = 0; t < 3; t++){
                    var arrTo = toInfo[t].split(':');
                    toComp.push(arrTo[1].substring(1,4));
                }
            } else {
                toComp = ['-','-','-'];
            }
        }
    };
    requestTO.open('GET', toUrl, false);
    requestTO.send(null);
    return toComp;
}

function sleep(ms){  // from http://www.digimantra.com/tutorials/sleep-or-wait-function-in-javascript/
	var dt = new Date();
	dt.setTime(dt.getTime() + ms);
	while (new Date().getTime() < dt.getTime());
}
function ns4tShorten(url){  // mturk-only URL shortener on Tjololo's server ns4t.net
    console.log("ns4tShorten function");
    var shortRes;
    var urlT = "http://ns4t.net/yourls-api.php" + "?action=shorturl&url=" + encodeURIComponent(url) + "&format=simple&title=MTurk&username=publicuser&password=publicpass";
    requestNs4t = new XMLHttpRequest();
    requestNs4t.onreadystatechange = function () {
        if (requestNs4t.readyState == 4) {
            if (requestNs4t.status == 200) {
                shortRes = requestNs4t.responseText;
                console.log("ns4t.net response: " + requestNs4t.status + " " + requestNs4t.statusText + " " + requestNs4t.responseText);
            } 
            else {
                console.log('ns4t.net unsuccessful: ' + requestNs4t.status + " " + requestNs4t.statusText);
            }
        }
    };
    requestNs4t.open('GET', urlT, false);
    requestNs4t.send(null);    
    return shortRes;
}
function tnyimShorten(url){  // Tny.im URL Shortener - http://tny.im/aboutapi.php - this is only possible this way because their server has the "Access-Control-Allow-Origin = *" headers enabled (the above TO mirror server does too)
    console.log("tnyimShorten function");
    var shortRes;
    var urlT = "https://tny.im/yourls-api.php" + "?action=shorturl&url=" + encodeURIComponent(url) + "&format=simple&title=MTurk";
    requestTnyim = new XMLHttpRequest();
    requestTnyim.onreadystatechange = function () {
        if (requestTnyim.readyState == 4) {
            if (requestTnyim.status == 200) {
                shortRes = requestTnyim.responseText;
                console.log("tny.im response: " + requestTnyim.status + " " + requestTnyim.statusText + " " + requestTnyim.responseText);
            } 
            else {
                console.log('tny.im unsuccessful: ' + requestTnyim.status + " " + requestTnyim.statusText);
            }
        }
    };
    requestTnyim.open('GET', urlT, false);
    requestTnyim.send(null);    
    return shortRes;
}
function googlShorten(url){  // Goo.gl URL Shortener
    console.log("googlShorten function");
    var shortRes;
    var urlG = "https://www.googleapis.com/urlshortener/v1/url";
    var requestGoogl = new XMLHttpRequest();
    requestGoogl.open("POST", urlG, false);
    requestGoogl.setRequestHeader("Content-Type", "application/json");
    requestGoogl.onreadystatechange = function() {
        if (requestGoogl.readyState == 4) {
            if (requestGoogl.status == 200) {
                shortRes = JSON.parse(requestGoogl.response).id;
                console.log("goo.gl response: " + requestGoogl.status + " " + requestGoogl.statusText + " " + JSON.parse(requestGoogl.response).id );
            } 
            else {
                console.log('goo.gl unsuccessful: ' + requestGoogl.status + " " + requestGoogl.statusText);
            }
        }
    };
    var data = new Object();
    data.longUrl = url;
    requestGoogl.send(JSON.stringify(data)); 

    return shortRes;
}
function shortenUrl(url){
    sleep(300);  // milliseconds delay - wait some milliseconds (currently less than 1/3rd of a second) between shortens to reduce chance of hitting usage limits
    var shortRes;
    shortRes = googlShorten(url);
    if ( shortRes === undefined ) {   // if you reached the Google URL shortener's temporary usage limits or the server is otherwise unavailable
        shortRes = ns4tShorten(url);
        if ( shortRes === undefined ) {   // if you reached the ns4t.net URL shortener's temporary limits or the server is otherwise unavailable
            shortRes = tnyimShorten(url);
            if ( shortRes === undefined ) {  // if you reached the tny.im URL shortener's temporary limits too or the server is otherwise unavailable
                shortRes = "(x)";
            }
        }
    }
    return shortRes;
}

// output display box
var ircexportdiv = document.createElement('div');
var ircexporttextarea = document.createElement('textarea');
ircexportdiv.style.position = 'fixed';
ircexportdiv.style.width = '500px';
ircexportdiv.style.height = '155px';
ircexportdiv.style.left = '50%';
ircexportdiv.style.right = '50%';
ircexportdiv.style.margin = '-250px 0px 0px -250px';
ircexportdiv.style.top = '300px';
ircexportdiv.style.padding = '5px';
ircexportdiv.style.border = '2px';
ircexportdiv.style.backgroundColor = 'black';
ircexportdiv.style.color = 'white';
ircexportdiv.style.zIndex = '100';
ircexportdiv.setAttribute('id','ircexport_div');
ircexportdiv.style.display = 'none';
ircexporttextarea.style.padding = '2px';
ircexporttextarea.style.width = '500px';
ircexporttextarea.style.height = '130px';
ircexporttextarea.title = 'IRC Export Output';
ircexporttextarea.setAttribute('id','ircexport_text');
ircexportdiv.textContent = 'IRC Export: Press Ctrl+C to (re-)copy to clipboard. Click textarea to close.';
ircexportdiv.style.fontSize = '12px';
ircexportdiv.appendChild(ircexporttextarea);
document.body.insertBefore(ircexportdiv, document.body.firstChild);
ircexporttextarea.addEventListener("click", function(){ ircexportdiv.style.display = 'none'; }, false);


function display(e){
    var theButton = e.target;
    theButton.style.backgroundColor = '#CC0000';
    
    var capHand = document.getElementById('capsule'+theButton.getAttribute("place")+'-0');
    var tBodies = capHand.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode;
    
    var capReq = tBodies.getElementsByClassName('requesterIdentity')[0].textContent;
    var capReqId = tBodies.getElementsByClassName('requesterIdentity')[0].parentNode.href.split('requesterId=')[1];
    
    var capTitle = capHand.textContent.trim();
    capTitle = capTitle.replace(/<(\w+)[^>]*>.*<\/\1>/gi, "").trim();  // addition to strip html tags and their contents, appearing inside the title link (re 10-20-2014 appearance of "<span class="tags"></span>")

    var capGId = 'unavailable';  // handle logged-out export requests for HITs with no preview/notqualified links
    if ( capHand.parentNode.parentNode.getElementsByClassName('capsulelink')[1].firstChild.nextSibling.href !== '' ) {  // if hit has a preview/notqualified link
        capGId = capHand.parentNode.parentNode.getElementsByClassName('capsulelink')[1].firstChild.nextSibling.href.split('=')[1];
        capGId = capGId.replace("&hitId", "");  // Amazon messed up the notqualified links, now looking like https://www.mturk.com/mturk/notqualified?hitGroupId=3ID43DSF4IQ1X8LO308D15ZSD5J5GX&hitId=3ID43DSF4IQ1X8LO308D15ZSD5J5GX ; this and the above split happening on = instead of a specific value address that
    }
    
    var capRew = tBodies.getElementsByClassName('reward')[0].textContent;

    var capTime = tBodies.getElementsByClassName('capsule_field_text')[2].textContent;

    var capAvailable = tBodies.getElementsByClassName('capsule_field_text')[4].textContent;

    var qualList = document.getElementById('capsule'+theButton.getAttribute("place")+'target').getElementsByTagName('tbody')[2];
    var qualColl = qualList.getElementsByTagName('td');
    var qualStart = 3;
    if ( document.getElementById('lnkWorkerSignin') ) { qualStart = 1; }  // handle logged-out export requests - difference in qual table coding
    var masterStat = '';
    for ( var m = qualStart; m < qualColl.length; m++ ) {
        if ( qualColl[m].textContent.indexOf('Masters') > -1 ) {
            masterStat = 'MASTERS • ';
        }
    }
    
    var capUrl = shortenUrl('https://www.mturk.com/mturk/preview?groupId='+capGId);
    var capReqUrl = shortenUrl('https://www.mturk.com/mturk/searchbar?selectedSearchType=hitgroups&requesterId='+capReqId);
    var hitLinkUnav = '';
    if ( capGId == 'unavailable' ) { capUrl = capReqUrl; hitLinkUnav = " (preview link unavailable)"; }  // handle logged-out export requests for HITs with no preview/notqualified links
    var toLink = shortenUrl('http://turkopticon.ucsd.edu/'+capReqId);
    var capToStats = getTO(capReqId);
    var shortUrlUnav = '';
    if ( (capUrl == '(x)') && (capGId != 'unavailable') ) { shortUrlUnav = ' \r\n^ https://www.mturk.com/mturk/preview?groupId='+capGId; }  // add the full-length preview link at the end if both URL shortener attempts failed
    
    var exString = masterStat + 'Requester: ' + capReq + ' ' + capReqUrl + ' • ' + 'HIT: ' + capTitle + ' ' + capUrl + hitLinkUnav + ' • ' + 'Pay: ' + capRew + ' • ' + 'Avail: ' + capAvailable + ' • ' + 'Time Limit: ' + capTime + ' • ' + 'TO: ' + 'Pay='+capToStats[1] + ' Fair='+capToStats[2] + ' Comm='+capToStats[0] + ' ' + toLink + shortUrlUnav ;
    GM_setClipboard(exString);
    window.setTimeout(function(){ theButton.style.backgroundColor = 'transparent'; }, 500);
    ircexporttextarea.textContent = exString;
    ircexportdiv.style.display = 'block';
    ircexporttextarea.select();
}