IRC Export (reformatted output mod)

Export HIT information for IRC chat

As of 2015-06-03. See the latest version.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name          IRC Export (reformatted output mod)
// @description   Export HIT information for IRC chat
// @version       3.8c
// @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. Please wait while shortened URLs are retrieved.';
    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;
    var toUrl2 = 'https://turkopticon.ucsd.edu/api/multi-attrs.php?ids='+f;
    var requestTO = new XMLHttpRequest();
    try{   // first try Miku's TO mirror server (istrack.in)
        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 < 4; 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;
    }
    catch(err){   // if mirror unavailable, try main TO server
        try{
            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 < 4; t++) {
                            var arrTo = toInfo[t].split(':');
                            toComp.push(arrTo[1].substring(1,4));
                        }
                    } 
                    else { toComp = ['-','-','-','-']; }
                }
            };
            requestTO.open('GET', toUrl2, false);
            requestTO.send(null);
            return toComp;
        }
        catch(err){   // if both unavailable, return 'na's
            toComp = ['na','na','na','na'];
            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 = "https://ns4t.net/yourls-api.php" + "?action=shorturl&url=" + encodeURIComponent(url) + "&format=simple&title=MTurk&username=publicuser&password=publicpass";
    var requestNs4t = new XMLHttpRequest();
    try{
        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;
    }
    catch(err){
        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";
    var requestTnyim = new XMLHttpRequest();
    try{
        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;
    }
    catch(err){
        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();
    try{
        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;
    }
    catch(err){
        return shortRes;
    }
}
function shortenUrl(url){
    sleep(500);  // milliseconds delay - wait some milliseconds (currently half a second) between shortens to reduce chance of hitting usage limits
    var shortRes;
    shortRes = ns4tShorten(url);
    if ( shortRes === undefined ) {   // if you reached the ns4t.net URL shortener's temporary usage limits or the server is otherwise unavailable
        shortRes = tnyimShorten(url);
        if ( shortRes === undefined ) {   // if you reached the tny.im URL shortener's temporary limits or the server is otherwise unavailable
            shortRes = googlShorten(url);
            if ( shortRes === undefined ) {  // if you reached the Google 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];
    // if on certain types of searches when logged out, more infernal Amazon-meddling may add a useless &state= value to the end of the requester link
    if ( capReqId.indexOf('&state=') > -1 )
    {
        capReqId = capReqId.split('&state')[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 hit has a preview or notqualified link
    if ( capHand.parentNode.parentNode.getElementsByClassName('capsulelink')[1].firstChild.nextSibling.href !== '' )  
    {
        // if this is a preview link
        if ( capHand.parentNode.parentNode.getElementsByClassName('capsulelink')[1].firstChild.nextSibling.href.indexOf('preview') > -1 )
        {
            capGId = capHand.parentNode.parentNode.getElementsByClassName('capsulelink')[1].firstChild.nextSibling.href.split('=')[1];
        }
        // if this is a notqualified link
        else if ( capHand.parentNode.parentNode.getElementsByClassName('capsulelink')[1].firstChild.nextSibling.href.indexOf('notqualified') > -1 )
        {
            capGId = capHand.parentNode.parentNode.getElementsByClassName('capsulelink')[1].firstChild.nextSibling.href.split('=')[1];
            // 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
            capGId = capGId.replace("&hitId", "").replace("&hitGroupId", "");  // added a removal of hitGroupId too since Amazon flipped the order of these on 6/2/15
        }
        // if this is a requestqualification link we shouldn't be on, but are anyway because of stuff Amazon screwed with on 6/2/15
        else if ( capHand.parentNode.parentNode.getElementsByClassName('capsulelink')[1].firstChild.nextSibling.href.indexOf('requestqualification') > -1 )
        {
            // go to the next link, the "(why?)" notqualified link instead
            capGId = capHand.parentNode.parentNode.getElementsByClassName('capsulelink')[1].firstChild.nextSibling.nextElementSibling.href.split('=')[1];
            // 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
            capGId = capGId.replace("&hitId", "").replace("&hitGroupId", "");  // added a removal of hitGroupId too since Amazon flipped the order of these on 6/2/15
        }
    }
    
    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];
    if ( document.location.href.indexOf('?last_hits_previewed') > -1 ) { qualList = document.getElementById('capsule'+theButton.getAttribute("place")+'target').getElementsByTagName('tbody')[1]; }
    var qualColl = qualList.getElementsByTagName('td');
    var qualStart = 3;
    if ( document.getElementById('lnkWorkerSignin') ) { qualStart = 1; }  // handle logged-out export requests - difference in qual table coding
    if ( document.location.href.indexOf('?last_hits_previewed') > -1 ) { qualStart = 2; }
    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 pandaUrl = shortenUrl('https://www.mturk.com/mturk/previewandaccept?groupId='+capGId);
    var capReqUrl = shortenUrl('https://www.mturk.com/mturk/searchbar?selectedSearchType=hitgroups&requesterId='+capReqId);
    var hitLinkUnav = '';
    if ( capGId == 'unavailable' ) { capUrl = capReqUrl;  pandaUrl = "";  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 all URL shortener attempts failed
    
    var exString = masterStat + 'Requester: ' + capReq + ' ' + capReqUrl + ' • ' + 'HIT: ' + capTitle + ' ' + capUrl + hitLinkUnav + ' • ' + 'Pay: ' + capRew + ' • ' + 'Avail: ' + capAvailable + ' • ' + 'Limit: ' + capTime + ' • ' + 'TO: ' + 'Pay='+capToStats[1] + ' Fair='+capToStats[2] + ' Comm='+capToStats[0] + ' ' + toLink + ' • ' + 'PandA: ' + pandaUrl + hitLinkUnav + shortUrlUnav ;
    if (GM_setClipboard) { GM_setClipboard(exString); }
    window.setTimeout(function(){ theButton.style.backgroundColor = 'transparent'; }, 500);
    ircexporttextarea.textContent = exString;
    ircexportdiv.style.display = 'block';
    ircexporttextarea.select();
}