NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name MTurk Great HIT Export // @namespace http://userscripts.org/users/522315 // @author ThirdClassInternationalMasterTurker edited by Tjololo12 // @description Export HIT description as vBulletin formatted text with turkopticon link, turkopticon info, and all relevant data // @include https://www.mturk.com/mturk/searchbar* // @include https://www.mturk.com/mturk/findhits* // @include https://www.mturk.com/mturk/viewhits* // @include https://www.mturk.com/mturk/viewsearchbar* // @include https://www.mturk.com/mturk/sortsearchbar* // @include https://www.mturk.com/mturk/sorthits* // @require https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js // @grant GM_getValue // @grant GM_setValue // @grant GM_deleteValue // @version 1.24 // ==/UserScript== // // 2012-11-19 0.2: Added customizable template // // 2012-11-20 0.3: Fixed: verifies that HIT link is correct // // 2012-11-26 0.4: Try to get requester and requesterId right even if some other script has changed the page. // Added requester link to default template. // // 2012-11-26 0.5: Partially works with Opera (No customisation) // // 2012-12-02 1.0: Added @downloadURL and @updateURL // (function () { var EDIT = false; var HITS = []; var HIT; var TO_BASE = "http://turkopticon.ucsd.edu/"; var API_BASE = "https://mturk-api.istrack.in/"; var API_MULTI_ATTRS_URL = API_BASE + "multi-attrs.php?ids="; DEFAULT_TEMPLATE = '[table][tr][td][b]Title:[/b] [url={link}][COLOR=blue]{title}[/COLOR][/url]\n'; DEFAULT_TEMPLATE += '[b]Requester:[/b] [url=https://www.mturk.com/mturk/searchbar?selectedSearchType=hitgroups&requesterId={requesterId}][COLOR=blue]{requester}[/COLOR][/url]'; DEFAULT_TEMPLATE += ' [{requesterId}] ([url='+TO_BASE+'{requesterId}][COLOR=blue]TO[/COLOR][/url])'; DEFAULT_TEMPLATE += '\n[b]TO Ratings:[/b]{to_stuff}'; DEFAULT_TEMPLATE += '\n[b]Description:[/b] {description}'; DEFAULT_TEMPLATE += '\n[b]Time:[/b] {time}'; DEFAULT_TEMPLATE += '\n[b]Hits Available:[/b] {hits_available}'; DEFAULT_TEMPLATE += '\n[b]Reward:[/b] [COLOR=green][b]{reward}[/b][/COLOR]'; DEFAULT_TEMPLATE += '\n[b]Qualifications:[/b] {qualifications}[/td][/tr][/table]'; var TEMPLATE; var EASYLINK; if (typeof GM_getValue === 'undefined') TEMPLATE = null; else { TEMPLATE = GM_getValue('HITExport Template'); EASYLINK = GM_getValue('HITExport Easylink'); } if (TEMPLATE == null) { TEMPLATE = DEFAULT_TEMPLATE; } function get_requester_id(s) { var idx = 12 + s.search('requesterId='); return s.substr(idx); } function getRequesterAnchorsAndIds(a) { var rai = {}; var re = new RegExp(/requesterId=/); var rf = new RegExp(/contact/); for (var i = 0; i < a.length; i++) { var href = a[i].getAttribute('href'); if (re.test(href) && !rf.test(href)) { //console.log(a[i].href); //testing var id = a[i].href.split('requesterId=')[1].split('&')[0] if (!rai.hasOwnProperty(id)) { rai[id] = []; } rai[id].push(a[i]); } } return rai; } function buildXhrUrl(rai) { var url = API_MULTI_ATTRS_URL; var ri = Object.keys(rai); for (var i = 0; i < ri.length; i++) { url += ri[i]; if (i < ri.length - 1) { url += ","; } } return url; } function makeXhrQuery(url) { var xhr = new XMLHttpRequest(); try{ xhr.open('GET', url, false); xhr.send(null); return $.parseJSON(xhr.response); } catch(err){ return "TO DOWN"; } } function getNamesForEmptyResponses(rai, resp) { for (var rid in rai) { if (rai.hasOwnProperty(rid) && resp[rid] == "") { //console.log(rai[rid][0].innerHTML.split("<")[1].split(">")[1]); //testing resp[rid] = $.parseJSON('{"name": "' + rai[rid][0].innerHTML.split("<")[1].split(">")[1] + '"}'); } } return resp; } function getKeys(obj) { var keys = []; for (var key in obj) { keys.push(key); } return keys; } function apply_template(hit_data) { var txt = TEMPLATE; var vars = ['title', 'requester', 'requesterId', 'description', 'reward', 'qualifications', 'link', 'time', 'hits_available', 'to_stuff', 'to_text', 'adfly']; var resp = null; if (txt.indexOf('{to_text}') >= 0 || txt.indexOf('{to_stuff}') >= 0){ var a = document.getElementsByTagName('a'); var rai = getRequesterAnchorsAndIds(a); var url = buildXhrUrl(rai); resp = getTOMulti(hit_data["requesterId"]); console.log(resp); if (resp != "TO DOWN" && resp != null) resp = getNamesForEmptyResponses(rai, resp); } var toText = ""; var toStuff = ""; var toData = ""; var numResp = (resp == null || resp == "TO DOWN" ? "n/a" : resp[hit_data["requesterId"]].reviews); if (resp == "TO DOWN"){ toStuff = " [URL=\""+TO_BASE+hit_data['requesterId']+"\"]TO down.[/URL]"; toText = toStuff; } else if (resp == null || resp[hit_data["requesterId"]].attrs == null && resp != "TO DOWN") { toStuff = " No TO "; toText = " No TO "; toStuff += "[URL=\""+TO_BASE+"report?requester[amzn_id]=" + hit_data['requesterId'] + "&requester[amzn_name]=" + hit_data['requester'] + "\"]"; toStuff += "(Submit a new TO rating for this requester)[/URL]"; } else { for (var key in resp[hit_data["requesterId"]].attrs) { //toText += "\n[*]"+key+": "+resp[hit_data["requesterId"]].attrs[key]+"\n"; var i = 0; var color = "green"; var name = key; var num = Math.floor(resp[hit_data["requesterId"]].attrs[key]); switch (key){ case "comm": name = "Communicativity"; break; case "pay": name = "Generosity"; break; case "fast": name = "Promptness"; break; case "fair": name = "Fairness"; break; default: name = key; break; } switch (num){ case 0: color = "red"; break; case 1: color = "red"; break; case 2: color = "orange"; break; case 3: color = "yellow"; break; default: break; } toText += (num > 0 ? "\n[color="+color+"]" : "\n"); for (i; i < num; i++){ toText += "[b]☢[/b]" } toText += (num > 0 ? "[/color]" : "") if (i < 5){ toText += "[color=white]"; for (i; i < 5; i++) toText += "[b]☢[/b]"; toText += "[/color]"; } toText += " "+Number(resp[hit_data["requesterId"]].attrs[key]).toFixed(2)+" "+name; toData += Number(resp[hit_data["requesterId"]].attrs[key]).toFixed(2) + ","; } //toText += "[/list]"; toText += (txt.indexOf('{to_stuff}') >= 0 ? "" : "\nNumber of Reviews: "+numResp+"\n[URL=\""+TO_BASE+"report?requester[amzn_id]=" + hit_data['requesterId'] + "&requester[amzn_name]=" + hit_data['requester'] + "\"](Submit a new TO rating for this requester)[/URL]"); toStuff = '\n[img]http://data.istrack.in/turkopticon.php?data=' + toData.slice(0,-1) + '[/img]'; toStuff += (txt.indexOf('{to_stuff}') >= 0 ? (txt.indexOf('{to_text}') >= 0 ? "" : toText) : ""); toStuff += "\nNumber of Reviews: "+numResp; toStuff += "[URL=\""+TO_BASE+"report?requester[amzn_id]=" + hit_data['requesterId'] + "&requester[amzn_name]=" + hit_data['requester'] + "\"]"; toStuff += "\n(Submit a new TO rating for this requester)[/URL]"; } if (hit_data["link"] == null) hit_data["title"] += (hit_data["title"].indexOf(" (Requester link substituted)") >= 0 ? "" : " (Requester link substituted)"); for (var i = 0; i < vars.length; i++) { t = new RegExp('\{' + vars[i] + '\}', 'g'); if (vars[i] == "to_stuff") { txt = txt.replace(t, toStuff); } else if (vars[i] == "to_text"){ txt = txt.replace(t, toText); } else txt = txt.replace(t, hit_data[vars[i]]); } textarea.value = txt; } function export_func(item) { return function () { HIT = item; EDIT = false; edit_button.textContent = 'Edit Template'; apply_template(HITS[HIT]); div.style.display = 'block'; textarea.select(); } } function hide_func(div) { return function () { if (EDIT == false) div.style.display = 'none'; } } function default_func() { return function () { GM_deleteValue('HITExport Template'); TEMPLATE = DEFAULT_TEMPLATE; EDIT = false; edit_button.textContent = 'Edit Template'; apply_template(HITS[HIT]); } } function edit_func() { return function () { if (EDIT == true) { EDIT = false; TEMPLATE = textarea.value; edit_button.textContent = 'Edit Template'; apply_template(HITS[HIT]); } else { EDIT = true; edit_button.textContent = 'Show Changes'; save_button.disabled = false; textarea.value = TEMPLATE; } } } function easy_func() { return function () { var input = prompt("Please enter your adfly easy link, or leave blank if you don't have one."); if (input.substring(input.length - 1) != "/") input += "/"; EASYLINK = input; GM_setValue('HITExport Easylink', EASYLINK); var url = EASYLINK + hit_data["link"]; hit_data["adfly"] = url; apply_template(hit_data); } } function save_func() { return function () { if (EDIT) TEMPLATE = textarea.value; GM_setValue('HITExport Template', TEMPLATE); } } for (var item = 0; item < 50; item++) { var tooltip = document.getElementById('requester.tooltip--' + item); if (tooltip == null) break; // no need to continue var titleElement = document.getElementById('capsule' + item + '-0'); var requesterId = tooltip.parentNode.parentNode.getElementsByTagName('a'); var hit_data = {}; hit_data.title = titleElement.textContent.trim(); for (var i = 0; i < requesterId.length; i++) { if (requesterId[i].href.match(/requesterId=/)) { hit_data.requesterId = get_requester_id(requesterId[i].href); if ( hit_data.requesterId.indexOf('&state=') > -1 ) { hit_data.requesterId = hit_data.requesterId.split('&state')[0]; } hit_data.requester = requesterId[i].textContent.trim(); break; } } hit_data.description = document.getElementById('description.tooltip--' + item).parentNode.parentNode.childNodes[3].textContent.trim(); hit_data.reward = document.getElementById('reward.tooltip--' + item).parentNode.parentNode.childNodes[3].textContent.trim(); hit_data.time = document.getElementById('duration_to_complete.tooltip--' + item).parentNode.parentNode.childNodes[3].textContent.trim(); hit_data.hits_available = document.getElementById('number_of_hits.tooltip--' + item).parentNode.parentNode.childNodes[3].textContent.trim(); //hit_data.to_stuff = toStuff; var linkElements = titleElement.parentNode.parentNode.getElementsByTagName('a'); if (linkElements != null) for (var i = 0; i < linkElements.length; i++) { if (linkElements[i] != null && linkElements[i].textContent == 'View a HIT in this group' || linkElements[i].textContent == 'Preview this HIT') { var url = EASYLINK + linkElements[i].href; hit_data.adfly = url; hit_data.link = linkElements[i].href; break; } if (linkElements[i] != null && linkElements[i].textContent == '(Why?)'){ var groupId = ""; var url = EASYLINK + linkElements[i].href; url = url.replace(/notqualified\?hitGroupId=([A-Z0-9]+)(&.+)?/,"preview?groupId=$1"); url = url.replace(/notqualified\?hitId=([A-Z0-9]+)(&.+)?/,"preview?groupId=$1"); url = url.replace(/\&hitGroupId=([A-Z0-9]+)(&.+)?/,""); url = url.replace(/\&hitId=([A-Z0-9]+)(&.+)?/,""); if (url.length == 0) url = "https://www.mturk.com/mturk/searchbar?selectedSearchType=hitgroups&requesterId="+hit_data.requesterId; hit_data.adfly = url; hit_data.link = linkElements[i].href; hit_data.link = hit_data.link.replace(/notqualified\?hitGroupId=([A-Z0-9]+)(&.+)?/,"preview?groupId=$1"); hit_data.link = hit_data.link.replace(/notqualified\?hitId=([A-Z0-9]+)(&.+)?/,"preview?groupId=$1"); hit_data.link = hit_data.link.replace(/\&hitGroupId=([A-Z0-9]+)(&.+)?/,""); hit_data.link = hit_data.link.replace(/\&hitId=([A-Z0-9]+)(&.+)?/,""); } } if (!hit_data.link){ hit_data.link = "https://www.mturk.com/mturk/searchbar?selectedSearchType=hitgroups&requesterId="+hit_data.requesterId; hit_data.adfly = EASYLINK + hit_data.link; hit_data.title = hit_data.title+" (Requester link substituted)"; } var qElements = document.getElementById('qualificationsRequired.tooltip--' + item).parentNode.parentNode.parentNode.getElementsByTagName('tr'); var qualifications = []; for (var i = 1; i < qElements.length; i++) { qualifications.push((qElements[i].childNodes[1].textContent.trim().replace(/\s+/g, ' ').indexOf("Masters") != -1 ? "[color=red][b]"+qElements[i].childNodes[1].textContent.trim().replace(/\s+/g, ' ')+"[/b][/color]" : qElements[i].childNodes[1].textContent.trim().replace(/\s+/g, ' '))); } hit_data.qualifications = (qualifications.join(', ') ? qualifications.join(', ') : "None"); HITS[item] = hit_data; button = document.createElement('button'); button.textContent = 'vB'; button.title = 'Export this HIT description as vBulletin formatted text'; 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.addEventListener("click", export_func(item), false); titleElement.parentNode.appendChild(button); } var div = document.createElement('div'); var textarea = document.createElement('textarea'); var div2 = document.createElement('label'); div.style.position = 'fixed'; div.style.width = '500px'; div.style.height = '235px'; div.style.left = '50%'; div.style.right = '50%'; div.style.margin = '-250px 0px 0px -250px'; div.style.top = '300px'; div.style.padding = '5px'; div.style.border = '2px'; div.style.backgroundColor = 'black'; div.style.color = 'white'; div.style.zIndex = '100'; textarea.style.padding = '2px'; textarea.style.width = '500px'; textarea.style.height = '200px'; textarea.title = '{title}\n{requester}\n{requesterId}\n{description}\n{reward}\n{qualifications}\n{link}\n{time}\n{hits_available}\n{to_stuff}\n{to_text}\n{adfly}'; div.textContent = 'Press Ctrl+C to copy to clipboard. Click textarea to close'; div.style.fontSize = '12px'; div.appendChild(textarea); var edit_button = document.createElement('button'); var save_button = document.createElement('button'); var default_button = document.createElement('button'); var easy_button = document.createElement('button'); edit_button.textContent = 'Edit Template'; edit_button.setAttribute('id', 'edit_button'); edit_button.style.height = '18px'; edit_button.style.width = '100px'; edit_button.style.fontSize = '10px'; edit_button.style.paddingLeft = '3px'; edit_button.style.paddingRight = '3px'; edit_button.style.backgroundColor = 'white'; save_button.textContent = 'Save Template'; save_button.setAttribute('id', 'save_button'); save_button.style.height = '18px'; save_button.style.width = '100px'; save_button.style.fontSize = '10px'; save_button.style.paddingLeft = '3px'; save_button.style.paddingRight = '3px'; save_button.style.backgroundColor = 'white'; save_button.style.marginLeft = '5px'; easy_button.textContent = 'Change Adfly Url'; easy_button.setAttribute('id', 'easy_button'); easy_button.style.height = '18px'; easy_button.style.width = '100px'; easy_button.style.fontSize = '10px'; easy_button.style.paddingLeft = '3px'; easy_button.style.paddingRight = '3px'; easy_button.style.backgroundColor = 'white'; easy_button.style.marginLeft = '5px'; default_button.textContent = ' D '; default_button.setAttribute('id', 'default_button'); default_button.style.height = '18px'; default_button.style.width = '20px'; default_button.style.fontSize = '10px'; default_button.style.paddingLeft = '3px'; default_button.style.paddingRight = '3px'; default_button.style.backgroundColor = 'white'; default_button.style.marginLeft = '5px'; default_button.title = 'Return default template'; div.appendChild(edit_button); div.appendChild(save_button); div.appendChild(default_button); div.appendChild(easy_button); save_button.disabled = true; div.style.display = 'none'; textarea.addEventListener("click", hide_func(div), false); edit_button.addEventListener("click", edit_func(), false); save_button.addEventListener("click", save_func(), false); default_button.addEventListener("click", default_func(), false); easy_button.addEventListener("click", easy_func(), false); document.body.insertBefore(div, document.body.firstChild); })(); function getTOMulti(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 rids = f.split(','); 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) toComp = $.parseJSON(requestTO.responseText); else toComp = null; } }; 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) toComp = $.parseJSON(requestTO.responseText); else toComp = null; } }; requestTO.open('GET', toUrl2, false); requestTO.send(null); return toComp; } catch(err){ // if both unavailable, return 'na's toComp = "TO DOWN"; return toComp; } } }