// ==UserScript== // @name Hermes HIT exporter // @namespace mobiusevalon.tibbius.com // @version 2.1 // @author Mobius Evalon // @description Adds an Export button to MTurk HIT capsules to share HITs on forums. // @license Creative Commons Attribution-ShareAlike 4.0; http://creativecommons.org/licenses/by-sa/4.0/ // @require https://code.jquery.com/jquery-1.12.4.min.js // @include /^https{0,1}:\/\/\w{0,}\.?mturk\.com\/mturk\/(?:searchbar|viewsearchbar|sortsearchbar|findhits|viewhits|sorthits)/ // @grant none // @downloadURL none // ==/UserScript== $(document).ready(function() { script_version = "2.1 beta"; function hit_info($element) { function highlight_qual(q) { var h = (q.indexOf("Masters") > -1); return ((h ? "[color=red]" : "")+q.collapse_whitespace()+(h ? "[/color]" : "")); } // basic HIT info that must be scraped off the page var obj = { hit_name:$("a.capsulelink[href='#']",$element).first().text().collapse_whitespace(), hit_id:$("a[href*='groupId']",$element).first().attr("href").match(/groupId=([A-Z0-9]{30})(?:&|$)/)[1], hit_desc:$("a[id*='description.tooltip']",$element).parent().next().text().collapse_whitespace(), hit_time:$("a[id*='duration_to_complete.tooltip']",$element).parent().next().text().collapse_whitespace(), hits_available:$("a[id*='number_of_hits.tooltip']",$element).parent().next().text().collapse_whitespace(), hit_reward:$("a[id*='reward.tooltip']",$element).parent().next().text().collapse_whitespace(), requester_name:$("a[href*='selectedSearchType=hitgroups']",$element).first().text().collapse_whitespace(), requester_id:$("a[href*='requesterId']",$element).first().attr("href").match(/requesterId=([A-Z0-9]{12,14})(?:&|$)/)[1] }; // link properties for convenience, since these are long URLs that only use one bit of previously collected info obj.preview_link = ("https://www.mturk.com/mturk/preview?groupId="+obj.hit_id); obj.panda_link = ("https://www.mturk.com/mturk/previewandaccept?groupId="+obj.hit_id); obj.requester_hits = ("https://www.mturk.com/mturk/searchbar?selectedSearchType=hitgroups&requesterId="+obj.requester_id); obj.to_reviews = ("https://turkopticon.ucsd.edu/"+obj.requester_id); // parse qualifications var $qual_anchor = $("a[id*='qualificationsRequired.tooltip']",$element); if($qual_anchor.parent().next().text().trim() === "None") obj.quals = "None"; else { var quals = []; $("tr:not(:first-of-type) td:first-of-type",$qual_anchor.closest("table")).each(function() {quals.push(highlight_qual($(this).text()));}); obj.quals = quals.join("; "); } obj.author_url = "https://greasyfork.org/en/users/9665-mobius-evalon"; obj.hermes_version = script_version; obj.hermes_url = "https://greasyfork.org/en/scripts/21175-hermes-hit-exporter"; // by default the user has provided no completion time estimate, so this block needs to not be displayed until the user provides that info obj.pph_block = ""; localStorage.hermes_hit = JSON.stringify(obj); } function get_template(t) { var format = (t || "vbulletin"); return (localStorage.getItem("hermes_"+format+"_template") || default_template(format)); } function default_template(format) { if(format === "vbulletin") return "[url={preview_link}][color=blue]{hit_name}[/color][/url] [[url={panda_link}][color=blue]PANDA[/color][/url]]\n"+ "[b]Reward[/b]: {hit_reward}\n"+ "[b]Time allowed[/b]: {hit_time}\n"+ "[b]Available[/b]: {hits_available}\n"+ "[b]Description[/b]: {hit_desc}\n"+ "[b]Qualifications[/b]: {quals}\n\n"+ "[b]Requester[/b]: [url={requester_hits}][color=blue]{requester_name}[/color][/url] [{requester_id}]\n"+ "[url={to_reviews}][color=blue][b]Turkopticon[/b][/color][/url]: \n"+ "[size=8px]Generated {date_time} with [url={hermes_url}][color=blue]Hermes HIT Exporter[/color][/url] {hermes_version} by [url={author_url}][color=blue]Mobius Evalon[/color][/url][/size]"; else if(format === "markdown") return "[{hit_name}]({preview_link}) \\[[PANDA]({panda_link})\\] \n"+ "**Reward**: {hit_reward} \n"+ "**Time allowed**: {hit_time} \n"+ "**Available**: {hits_available} \n"+ "**Description**: {hit_desc} \n"+ "**Qualifications**: {quals}\n\n"+ "**Requester**: [{requester_name}]({requester_hits}) \\[{requester_id}\\] \n"+ "[**Turkopticon**]({to_reviews}): \n"+ "^Generated {date_time} with [Hermes HIT Exporter]({hermes_url}) {hermes_version} by [Mobius Evalon]({author_url})"; } function reset_interface() { $("#hhe_edit_template").hide(); $("#hhe_export_output").hide(); $("#hhe_mode_swap").text("Edit"); $("#hhe_update_time").prop("disabled",true); $("#hhe_completion_time").val(""); $("#hhe_export_format").prop("disabled",true).val(localStorage.hermes_export_format || "vbulletin"); } function display_template() { function to_symbol(n) { n = Math.floor(n*1); var symbol = "☯", colored = "", white = ""; while(colored.length < n) colored += symbol; while((colored.length+white.length) < 5) white += symbol; if($("#hhe_export_format").val() === "markdown") return colored; // markdown doesn't do colors else { var color = (n >= 4 ? "green" : (n <= 2 ? "red" : "orange")); return (colored.length ? ("[color="+color+"]"+colored+"[/color]") : "")+(white.length ? ("[color=white]"+white+"[/color]") : ""); } } var obj = localstorage_obj("hermes_hit"), template = get_template($("#hhe_export_format").val()); $("#hhe_update_time, #hhe_export_format").prop("disabled",false); $.each(obj,function(key,val) { if(key.slice(-6) === "_block") template = template.replace(new RegExp(("<"+key+":.*?>"),"gi"),val); else template = template.replace(new RegExp(("\\{"+key+"\\}"),"gi"),val); }); // date_time has to handled here because putting it in the hit obj would cache the data instead of // using current information. the other replace is to remove unused blocks template = template.replace(/{date_time}/ig,new Date().toString()).replace(/<.+?_block:(.*?)>/gi,"$1"); // the symbol lists have to be done here because of template changing $.each(["pay","fair","fast","comm"],function(key,val) { template = template.replace(new RegExp(("\\{to_"+val+"_symbols\\}"),"gi"),to_symbol(obj["to_"+val])); }); $("#hhe_export_output").show().text(template); } function turkopticon() { var to_mirrors = ["https://mturk-api.istrack.in/multi-attrs.php?ids=", "https://turkopticon.ucsd.edu/api/multi-attrs.php?ids="], hit_obj = localstorage_obj("hermes_hit"); function mirror_domain(s) { return s.match(/^https{0,1}:\/\/(.+?)\//i)[1]; } function exit() { localStorage.hermes_hit = JSON.stringify(hit_obj); display_template(); } function to_request(url) { $.ajax({async:true, method:"GET", url:(url+hit_obj.requester_id) }) .fail(function() { console.log("Hermes HIT exporter: attempt to gather Turkopticon data from "+mirror_domain(url)+" mirror failed"); var idx = (to_mirrors.indexOf(url)+1); if(idx < to_mirrors.length) { console.log("Hermes HIT exporter: attempting Turkopticon data request from mirror "+mirror_domain(to_mirrors[idx])+"..."); to_request(to_mirrors[idx]); } else { hit_obj.to_block = "[Error]"; console.log("Hermes HIT exporter: attempts to gather Turkopticon data from all available mirrors has failed"); exit(); } }) .done(function(response) { console.log("Hermes HIT exporter: successfully queried Turkopticon data from "+mirror_domain(url)+" mirror"); var to_info = JSON.parse(response); if($.type(to_info) === "object" && to_info.hasOwnProperty(hit_obj.requester_id)) { if($.type(to_info[hit_obj.requester_id]) === "object") { hit_obj.to_pay = to_info[hit_obj.requester_id].attrs.pay; hit_obj.to_fair = to_info[hit_obj.requester_id].attrs.fair; hit_obj.to_fast = to_info[hit_obj.requester_id].attrs.fast; hit_obj.to_comm = to_info[hit_obj.requester_id].attrs.comm; hit_obj.to_graphic = ("http://data.istrack.in/turkopticon.php?data="+hit_obj.to_comm+","+hit_obj.to_pay+","+hit_obj.to_fair+","+hit_obj.to_fast); } else { hit_obj.to_block = "[None]"; console.log("Hermes HIT exporter: requester "+hit_obj.requester_name+" has no Turkopticon data"); } } else console.log("Hermes HIT exporter: Turkopticon data returned from "+mirror_domain(url)+" mirror is malformed"); exit(); }); } $("div#hermes_export_window textarea#hhe_export_output").show().text("Gathering Turkopticon data for "+hit_obj.requester_name+"..."); to_request(to_mirrors[0]); } function json_obj(json) { var obj; if(typeof json === "string" && json.trim().length) { try {obj = JSON.parse(json);} catch(e) {console.log("Malformed JSON object. Error message from JSON library: ["+e.message+"]");} } return obj; } function localstorage_obj(key) { var obj = json_obj(localStorage.getItem(key)); if(typeof obj !== "object") localStorage.removeItem(key); return obj; } function zero_pad(a,l,d) { if($.type(a) !== "string") a = (""+a); var p = ""; for(var i=a.length;i -1) return true; return false; }; $("head").append( $("