- // ==UserScript==
- // @name HIT Forker
- // @version 1.2.1
- // @description Monitors mturk.com for HITs
- // @author ThisPoorGuy
- // @icon https://i.imgur.com/RaPUMRP.png
- // @include https://worker.mturk.com/?finder_beta_test
- // @include https://worker.mturk.com/?hit_forker
- // @grant GM_log
- // @grant GM_setClipboard
- // @grant GM_xmlhttpRequest
- // @connect turkerview.com
- // @require https://code.jquery.com/jquery-3.1.0.min.js
- // @require https://cdnjs.cloudflare.com/ajax/libs/dompurify/1.0.8/purify.min.js
-
- // @namespace https://gf.qytechs.cn/users/163167
- // ==/UserScript==
-
- // Acknowledgements
- // The core of this script was forked/stolen/adapted from Kadauchi's Hit Finder Beta script. Coding assistance in spots
- // provided by Salem Beats and ChrisTurk. TurkerView was created by ChrisTurk. This script hooks into JR Panda Crazy
- // Slothbear provided the code for text to speech, thanks!
-
- // Changelog
- // 1.2.1 - Fixed bug with TO API call to catch JSON error (Thanks THFYM for the tip!)
- // 1.2 - Added option to turn off TurkerView if you desire such things.
- // 1.1.1 = Fixed an issue with the TV API where it will stop if it encounters an error
- // 1.1 - Added new TurkerView API code
- // 1.0.6.1 - Further input sanatization improvements
- // 1.0.5 - Minor update to change the soundjay links to https to stop mixed content complaining.
- // 1.0.4 - Added an I button to the HIT log/HIT list so you can just click once to add something to the include list.
- // 1.0.3 - Further work on input sanitization
- // 1.0.2 - Fixed the issue where some asshat decided to inject code into a HIT name. THIS IS WHY WE CAN'T HAVE NICE THINGS.
- // 1.0.1 - Fixed IRC Export function. You're welcome one guy using IRC exports.
- // 1.0.0 - Added Text to speech for include list hits. There's a TTS checkbox in the show config section, this will override any sounds set up on your include list with a
- // text to speech notification. In order for the alert to trigger you need an include list entry with play sound enabled. Which sound you pick won't matter as this
- // will ignore that setting and use a vocal alert. Thanks to slothbear for the code.
- // 0.8.1.2 - Fixed an issue exporting HITS that have quotes in the title.
- // 0.8.1.1 - Added a limit to the number of characters you can stick into the fields on adding something to the block list to prevent accidental pasting of a block list import into the wrong spot.
- // 0.8.1 - Fixed a couple of export formatting bugs.
- // 0.8.0 - Added the ability to press a button to launch a qualification test if you don't qualify for something and a test is availible.
- // Working on adding requesting for auto-grant quals, but that's...trickier.
- // 0.7.6 - Fixed issue with the search qualified check box not working.
- // 0.7.5 - Added abilible hits to the Log display. Note this only shows the data from the time when the HIT was first seen, not any subsequent scans of it.
- // 0.7.4 - Removed column for masters, it wasn't used for anything and was broken anyway. Also removed hide masters because it worked off of that code, which wasn't working anyway
- // 0.7.3 - Returned a semi-colon to it's rightful position, even though it wasn't missed
- // 0.7.2 - Made it so that the Panda button sets pandas without once=true set. Whoops.
- // 0.7.0 - Big under the hood changes with how TV and TO review scores are gathered.
- // 0.6.5 - Further modifications to prevent availibility of external sites causing HF to stop randomly.
- // 0.6.4 - Send RequesterID over to PandaCrazy along with the other info.
- // 0.6.3 - Bringing PC functionality in house
- // 0.6.1 - Fixed panda button shading
- // 0.6.0 - Re-jiggered panda crazy integration code to use Salem's PC library. Now detects if panda crazy is actually running when you click.
- // 0.5.3 - Slight modifications to break integration with JR Panda Crazy, due to a memory leak issue. Will reach out to dev to see if we can clear it up and be happy together...
- // 0.5.2 - Code cleanup.
- // 0.5.1 - Fixed the panda buttons on the Found hits table.
- // 0.5.0 - Hitting the panda button now sends full HIT name, pay and requester name info to panda crazy too. Have you noticed these version number leaps are pretty arbitratry?
- // - Fixed a stupid typo in a variable name.
- // 0.4.3 - Switched TO request from a .get call to a .ajax call with a timeout to prevent the entire thing from exploding when TO's servers do.
- // 0.4.2 - Link to TV Requester profile in export.
- // 0.4.1 - Show/Hide HITs and Logged Hits settings are now saved across sessions
- // 0.4.0 - Blocking a HIT or a Requester will now remove that Hit or all hits from said requester from display in the Hit Log
- // 0.3.5 - Added a button to hide the new HITS table. Moved the button to hide the logged hits for consistancy.
- // 0.3.2 - Modified icon for desktop notifications. Added Requester TV score to hit export
- // 0.3.1 - Fix for amazon screwing with things. Thanks ChrisTurk!
- // 0.3.0 - Under the hood changes, removed code for running on www, added new launch URL, old ?finder_beta will be phased out eventually
- // 0.2.9 - Now acceptable to people with red/green color blindness!
- // 0.2.6 - Fixed a minor error which caused colors to not work properly.
- // 0.2.5 - Changed Coloration to respect TV reviews FIRST and then fall back on TO Values. Also changed colors.
- // 0.2.0 - Added TurkerView Hourly ratings to HIT results, fixed export links.
- // 0.1.5 - Some minor UI tweaks
- // 0.1.4 - Added some indication that you have already clicked a button to send HIT to PC. Only works in log currently.
- // 0.1.3 - Fixed issue with the Panda buttons in the HIT log not having the right GID
- // 0.1.2 - Fixed an issue with HITs that have double quotes in the title not working with the ignore hit by title button. I think.
- // 0.1.1 - Cleaned up the header, removed unused audio files
- // 0.1.0 - Made modifications to launch links with worker website. Added buttons to send information to PandaCrazy directly instead of copying link
- // TODO:
- // Remove www code
- // Clean up interface
- // Delete the above todos because they're already done.
-
- const ver = GM_info.scriptMetaStr.match(/version.*?(\d+.*)/)[1];
- var worker = true;
-
- var _config = JSON.parse(localStorage.getItem('_finder')) || {};
- _config.tv_api_key = localStorage.getItem('turkerview_api_key') || '';
- var blocklist = JSON.parse(localStorage.getItem('_finder_bl')) || {};
- var includelist = JSON.parse(localStorage.getItem('_finder_il')) || {};
-
- // Compatability check
- if (_config.version !== '1.1') { _config = {}; }
-
- var config = {
- version : _config.version || '1.1',
- delay : _config.delay || '3',
- type : _config.type || 'LastUpdatedTime%3A1&pageSize=',
- size : _config.size || '25',
- rew : _config.rew || '0.00',
- avail : _config.avail || '0',
- mto : _config.mto || '0.00',
- alert : _config.alert || '0',
- qual : _config.hasOwnProperty('qual') ? _config.qual : true,
- new : _config.hasOwnProperty('new') ? _config.new : true,
- newaudio : _config.newaudio || 'beep',
- pb : _config.hasOwnProperty('pb') ? _config.pb : false,
- to : _config.hasOwnProperty('to') ? _config.to : false,
- tv : _config.hasOwnProperty('tv') ? _config.tv : true,
- nl : _config.hasOwnProperty('nl') ? _config.nl : false,
- bl : _config.hasOwnProperty('bl') ? _config.bl : false,
- m : _config.hasOwnProperty('m') ? _config.m : false,
- tts : _config.hasOwnProperty('tts') ? _config.tts : false,
- push : _config.push || 'access_token_here',
- tv_api_key : _config.tv_api_key || '',
- disable_tv : _config.disable_tv || false,
- theme : _config.theme || 'default',
- custom : _config.custom || {main: 'FFFFFF', primary: 'CCCCCC', secondary: '111111', text: '000000', link: '0000EE', visited: '551A8B', prop : false},
- to_theme : _config.to_theme || '1',
- h_hidden : _config.h_hidden || '0',
- l_hidden : _config.l_hidden || '0'
- };
- console.log(config);
- console.log(config.tv_api_key);
- var themes = {
- 'default' : {main: 'FFFFFF', primary: 'CCCCCC', secondary: '111111', menu: '373b44', menutext: 'FFFFFF', text: '000000', link: '0000EE', visited: '551A8B', prop : true},
- 'light' : {main: 'FFFFFF', primary: 'CCCCCC', secondary: '111111', menu: '373b44', menutext: 'FFFFFF', text: '000000', link: '0000EE', visited: '551A8B', prop : true},
- 'dark' : {main: '404040', primary: '666666', secondary: 'FFFFFF', menu: '202020', menutext: 'FFFFFF', text: 'FFFFFF', link: 'FFFFFF', visited: 'B3B3B3', prop : true},
- 'darker' : {main: '000000', primary: '262626', secondary: 'FFFFFF', menu: '373b44', menutext: 'FFFFFF', text: 'FFFFFF', link: 'FFFFFF', visited: 'B3B3B3', prop : true},
- 'custom' : config.custom
- };
-
- var turkerview = { };
- var turkerview_update = 0;
- var requesters = [ ];
- var tvTimeoutCache = [ ];
-
- var searches = 0,
- logged = 0,
- hitlog = {},
- noti_delay = [],
- push_delay = [];
-
- const ViewHeaders = new Headers([
- ['X-VIEW-KEY', config.tv_api_key],
- ['X-APP-KEY', 'HIT Forker'],
- ['X-APP-VER', ver] //SemVer
- ]);
-
- // General Configuration variables
- var url, upd, num, rew, minrew, searchqual, pandaurl;
-
- url = 'https://worker.mturk.com/?';
- pandaurl = 'https://worker.mturk.com';
- upd = '&sort=updated_desc&page_size=';
- num = '&sort=num_hits_desc&page_size=';
- rew = '&sort=reward_desc&page_size=';
- minrew = '&filters%5Bmin_reward%5D=';
- searchqual = '&filters%5Bqualified=';
-
- var PandaCrazy = (function createPandaCrazy() {
- let _self = this;
-
- let _lastSentPingTime;
- let _lastReceivedPongTime;
-
- let _onlineSinceLastPing;
-
- let _pcListener;
-
- const MAX_WAIT_FOR_PANDA_CRAZY_RESPONSE_MS = 1000;
-
- function ping() {
- _lastSentPingTime = Date.now();
- localStorage.setItem("JR_message_ping_pandacrazy", `{"theTarget": "${Math.random()}"}`);
- }
-
- function hasIndicatedOnlineSinceLastPing() {
- if(_lastSentPingTime !== undefined && _lastReceivedPongTime !== undefined) {
- return _lastReceivedPongTime >= _lastSentPingTime;
- }
- else {
- return undefined;
- }
- }
-
- function online() {
-
- function respondToStorage(resolve, reject, e) {
- if(e.key.includes("JR_message_pong") && Boolean(e.newValue)) {
-
- _lastReceivedPongTime = Date.now();
-
- let pongData = JSON.parse(e.newValue);
-
- let lag = Number(pongData.time) - Number(_lastReceivedPongTime);
-
- if(hasIndicatedOnlineSinceLastPing()) {
- resolve("online");
- }
- }
- }
-
- let isOnlinePromise = new Promise((resolve, reject) => {
-
- setTimeout(() => {reject("timeout");}, MAX_WAIT_FOR_PANDA_CRAZY_RESPONSE_MS);
-
- if(_pcListener) {window.removeEventListener("storage", _pcListener);}
-
- _pcListener = respondToStorage.bind(window, resolve, reject);
-
- window.addEventListener("storage", _pcListener);
-
- /*
- window.addEventListener("storage", e => {
-
- // console.log("Storage Event", e);
-
- if(e.key.includes("JR_message_pong") && Boolean(e.newValue)) {
-
- _lastReceivedPongTime = Date.now();
-
- let pongData = JSON.parse(e.newValue);
-
- let lag = Number(pongData.time) - Number(_lastReceivedPongTime);
-
- if(hasIndicatedOnlineSinceLastPing()) {
- resolve("online");
- }
- }
- });
- */
- });
-
- ping();
-
- return isOnlinePromise;
- }
-
- function addJob(gid, once, metadata) {
- let commandString = once ? "addOnceJob" : "addJob";
-
- localStorage.setItem("JR_message_pandacrazy", JSON.stringify({
- time: Date.now(),
- command: commandString,
- data: {
- groupId: gid,
- title: (metadata ? metadata.hitTitle || metadata.title : undefined),
- requesterName: (metadata ? metadata.requesterName : undefined),
- requesterId: (metadata ? metadata.requesterID || metadata.requesterId || metadata.rid : undefined),
- pay: (metadata ? metadata.hitValue || metadata.pay : undefined),
- duration: (metadata ? metadata.duration : undefined),
- hitsAvailable: (metadata ? metadata.hitsAvailable : undefined)
- }
- }));
- }
-
- function startJob(gid) {
- localStorage.setItem("JR_message_pandacrazy", JSON.stringify({
- time: Date.now(),
- command: "startcollect",
- data: {
- groupId: gid
- }
- }));
- }
-
- return {
- addJob,
- startJob,
- ping,
- online
- };
- })();
-
- const SPEECH_VOICE = 3; //0 - 21ish
- const SPEECH_RATE = 0.9; //1 - 10 (default is 1)
- const SPEECH_VOLUME = 1; //0 - 1 (default is 1)
- const SPEECH_LANG = 'en-US'; //(default is 'en')
-
-
-
- //this is what does it all!
- unsafeWindow.slothbearsTTS = function(obj) {
- let phrase = "Hit Found!" + obj.name;
- var speech = new Speech();
- if (speech.supported()) {
- speech.speak(phrase);
- }
- };
-
-
-
- var Speech = function() {
- };
-
- Speech.voices = null;
-
- (function() {
- if ('speechSynthesis' in window) {
- // First call to getVoices may be null...later an event indicates when it is loaded
- Speech.voices = window.speechSynthesis.getVoices();
-
- // Save voices when loaded after first call
- window.speechSynthesis.onvoiceschanged = function() {
- Speech.voices = window.speechSynthesis.getVoices();
- };
- }
- })();
-
- Speech.prototype.supported = function() {
- return Speech.voices !== null;
- };
-
- Speech.prototype.speak = function(text) {
- if (Speech.voices !== null) {
- var speech = new SpeechSynthesisUtterance(text);
-
- speech.rate = SPEECH_RATE;
- speech.voice = speechSynthesis.getVoices()[SPEECH_VOICE];
- speech.lang = SPEECH_LANG;
- speech.volume = SPEECH_VOLUME;
- window.speechSynthesis.speak(speech);
- }
- };
-
- $('head').html(
- '<title>HIT Forker</title>' +
- '<link rel="icon" type="image/jpg" href="http://nopurpose.org/stuff/avatars/Lj21396.gif">' +
- '<base target="_blank">' +
-
- '<audio id="audio_1"><source src="https://www.soundjay.com/button/sounds/button-1.mp3" type="audio/mpeg"></audio>' +
- '<audio id="audio_2"><source src="https://www.soundjay.com/button/sounds/button-3.mp3" type="audio/mpeg"></audio>' +
- '<audio id="audio_3"><source src="https://www.soundjay.com/button/sounds/button-4.mp3" type="audio/mpeg"></audio>' +
- '<audio id="audio_4"><source src="https://www.soundjay.com/button/sounds/button-5.mp3" type="audio/mpeg"></audio>' +
- '<audio id="audio_beep"><source src="https://www.soundjay.com/button/sounds/beep-21.mp3" type="audio/mpeg"></audio>' +
- '<audio id="audio_beepbeep"><source src="https://www.soundjay.com/button/sounds/beep-24.mp3" type="audio/mpeg"></audio>' +
- '<audio id="audio_click"><source src="https://www.soundjay.com/button/sounds/button-20.mp3" type="audio/mpeg"></audio>' +
-
- '<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css" rel="stylesheet">' +
- '<style id="css" type="text/css">'
- );
-
- $('body').on('click', '.closeTvAlert', function(){
- $(this).parent().parent().hide();
- });
-
- $('body').html(
- // Main
- '<div style="margin-bottom: 5px; text-align:right;" id="menubar">' +
- '<div style="position: absolute; top: 32px width: 100px; font-size: 14pt; font-weight: bold;" id="menu_title">HIT Forker</div>'+
- '<div style="line-height: 30px; margin-right:5px;">'+
- '<button id="scan_button" style="margin-right: 5px;">Start</button>' +
- '<button id="bloc_button" style="margin-right: 5px;">Block List</button>' +
- '<button id="incl_button" style="margin-right: 5px;">Include List</button>' +
- '<button id="sett_button" style="margin-right: 5px;">Advanced Settings</button>' +
- '<button id="conf_button" style="margin-right: 5px;">Show Config</button>' +
-
- '</div></div>' +
-
- // Config
- '<div id="config" style="position: absolute; top: 37px; right: 5px; margin-bottom: 5px;" class="hidden">' +
-
- '<div style="margin-bottom: 5px;">' +
- '<label style="margin-right: 5px; display: inline-block; border-bottom: 1px solid;" title="Delay in seconds between searches.">Search Delay: ' +
- '<input id="delay" style="width: 50px;" type="number" step="1" min="1" value="' + config.delay + '">' +
- '</label>' +
-
- '<label style="margin-right: 5px; display: inline-block; border-bottom: 1px solid;" title="Filter HITs by minimum reward.">Min Reward: ' +
- '<input id="min_rew" style="width: 50px;" type="number" step="0.01" min="0" value="' + config.rew + '">' +
- '</label>' +
-
- '<label style="margin-right: 5px; display: inline-block; border-bottom: 1px solid;" title="Filter HITs by minimum available.">Min Avail: ' +
- '<input id="min_avail" style="width: 50px;" type="number" step="1" min="0" value="' + config.avail + '">' +
- '</label>' +
-
- '<label style="margin-right: 5px; display: inline-block; border-bottom: 1px solid;" title="Filter HITs by minimum TO pay.">Min TO: ' +
- '<input id="min_to" style="width: 50px;" type="number" step="0.1" min="0" max="5" value="' + config.mto + '">' +
- '</label>' +
-
- '<label style="margin-right: 5px; display: inline-block; border-bottom: 1px solid;" title="Search for this many HITs.">Size: ' +
- '<input id="size" style="width: 50px;" type="number" step="1" min="1" max="100" value="' + config.size + '">' +
- '</label>' +
-
- '<label style="margin-right: 5px; display: inline-block; border-bottom: 1px solid;" title="Sort HITs by (Latest / Most Available / Highest Reward)">Sort by: ' +
- '<select id="type" value="' + config.type + '">' +
- '<option value="' + upd + '">Latest</option>' +
- '<option value="' + num + '">Most Available</option>' +
- '<option value="' + rew + '">Reward (Most)</option>' +
- '</select>' +
- '</label>' +
-
- '<label style="margin-right: 0px; display: inline-block; border-bottom: 1px solid;" title="Only show HITs that you are for.">Qualified' +
- '<input id="qual" type="checkbox" ' + (config.qual ? 'checked' : '') + '>' +
- '</label>' +
- '</div>' +
-
- '<div style="margin-bottom: 5px;">' +
- '<label style="margin-right: 5px; display: inline-block; border-bottom: 1px solid;" title="Delay in seconds between desktop notifications and sound alerts for an include list match.">Alert Delay: ' +
- '<input id="alert_delay" style="width: 50px;" type="number" step="1" min="0" value="' + config.alert + '">' +
- '</label>' +
-
- '<label style="margin-right: 5px; display: inline-block; border-bottom: 1px solid;" title="Make a sound when a new HIT is found.">Sound On New HIT ' +
- '<input id="new_sound" type="checkbox" ' + (config.new ? 'checked' : '') + '>' +
- '<select id="new_audio" value="' + config.newaudio + '">' +
- //'<option value="default">Default</option>' +
- '<option value="beep">Beep</option>' +
- '<option value="beepbeep">Beep Beep</option>' +
- //'<option value="ding">Ding</option>' +
- //'<option value="squee">Squee</option>' +
- '<option value="click">Click</option>' +
- '</select>' +
- '</label>' +
-
- '<label style="margin-right: 5px; display: inline-block; border-bottom: 1px solid;" title="Allow include list to send a TTS notification when matched">TTS ' +
- '<input id="tts" type="checkbox" ' + (config.tts ? 'checked' : '') + '>' +
- '</label>' +
-
- '<label style="margin-right: 5px; display: inline-block; border-bottom: 1px solid;" title="Allow inludelist matches to send Pushbullet notifications if enabled for that match.">Pushbullet ' +
- '<input id="pb" type="checkbox" ' + (config.pb ? 'checked' : '') + '>' +
- '</label>' +
-
- '<label style="margin-right: 5px; display: inline-block; border-bottom: 1px solid;" title="Use turkopticon.">Enable TO ' +
- '<input id="to" type="checkbox" ' + (config.to ? 'checked' : '') + '>' +
- '</label>' +
-
- '<label style="margin-right: 5px; display: inline-block; border-bottom: 1px solid;" title="Hide all HITs that do not match your include list.">Hide Non Include List ' +
- '<input id="nl_hide" type="checkbox" ' + (config.nl ? 'checked' : '') + '>' +
- '</label>' +
-
- '<label style="margin-right: 5px; display: inline-block; border-bottom: 1px solid;" title="Hide HITs that match your block list.">Hide Block List ' +
- '<input id="bl_hide" type="checkbox" ' + (config.bl ? 'checked' : '') + '>' +
- '</label>' +
-
- '</div>' +
-
- '</div>' +
-
- '<div id="TVAlert" style="background-color: #dff0d8; border-color: #d0e9c6;' + (((config.tv_api_key == '' || config.tv_api_key.length != 40) && !config.disable_tv) ? `` : ` display: none; `) +' color: #3c763d; padding: 15px; margin-bottom: 1rem; border: 1px solid transparent; border-radius: 2px; margin: auto; width: 60%; padding-top: 10px; padding-bottom: 10px;">' +
- '<h4 style="font-size: 0.857rem; margin-bottom: 0.5rem; margin-top: 0.5rem;">TurkerView API Changes (<span class="closeTvAlert" style="cursor: pointer;">Dismiss</span>)</h4>' +
-
- `<small>
- <p>Sorry for the intrusion, but we're expanding our services & infrastructure and making huge improvements to the way we deliver information & data to Turkers in 2019!</p>
- <p>HIT Forker has been updated to function with TurkerView's new View API [<a href="https://forum.turkerview.com/threads/hit-forker-update.2025/" target="_blank">details here</a>]
- <p>TVJS 10 is out! You can read change details <a href="https://forum.turkerview.com/threads/turkerviewjs-10.2010/" target="_blank">here</a> - including improvements to approval (AA) time tracking! You can find more information about the full API changes <a href="https://forum.turkerview.com/threads/view-api-details.2012/" target="_blank" style="text-decoration: underline;">on our announcement here</a>.</p>
- <p>Make sure to register & get your new access keys to our upgraded API by <a href="https://turkerview.com/account/api/" target="_blank" style="text-decoration: underline;">visiting your account dashboard</a>. We'll stop displaying this as soon as you do, but the script wont be able to retrieve TV data after February 1st without an API Key.</p>
- </small><form action="saveForkerApiForm" onsubmit="return false;">
- <input type="text" class="form-control" style="max-width: 50%; margin-top: 5px; margin-bottom: 5px;">
- <button type="submit" class="btn btn-primary">Save API Key</button>
- </form>
- <script>
- $('form[action*=saveForkerApiForm]').submit(function(e){
- e.preventDefault();
- let api_key = $(this).find('input[type=text]').val().trim();
- console.log(api_key);
- if (api_key.length == 40){
- localStorage.setItem('turkerview_api_key', api_key);
- alert('Awesome, we saved your API key for future use! HIT Forker will reload now.');
- window.location.reload();
- } else {
- alert("We cannot save the provided key as it isn't valid.");
- }
- });
- </script>` +
-
- '</div>'+
-
- '<div id="TVErrorMessage" style="display: none; background-color: #f2dede; border-color: #ebcccc; color: #a94442; padding: 15px; margin-bottom: 1rem; border: 1px solid transparent; border-radius: 2px; margin: auto; width: 60%; padding-top: 10px; padding-bottom: 10px;">' +
- '<h4 style="font-size: 0.857rem; margin-bottom: 0.5rem; margin-top: 0.5rem;">TurkerView API Error (<span class="closeTvAlert" style="cursor: pointer;">Dismiss</span>)</h4>' +
- '<p style="margin-bottom: 0.5rem; margin-top: 0.5rem;">Error Message.</p>' +
- '</div>'+
- // HITs
- '<div id="latest_hits">' +
- '<div style="border-bottom: 3px solid; margin-bottom: 5px;">' +
- '<span style="font-size: 20px; font-weight: bold;">HITs</span>' +
- '<span id="hits_data" style="font-size: 11px;"></span>' +
- '<span id="hits_controls" style="float: right"><button id="hits_button" style="margin-right: 5px;">Hide New HITs</button></span>' +
- '</div>' +
- '<div id="hits_hidden" style="text-align: center; display: none;">--- HITS HIDDEN ---</div>' +
- '<div id="hits_table">' +
- '<div>' +
- '<div style="overflow: hidden; white-space: nowrap;">' +
- '<div style="float: left; width: calc(100% - 330px);">' +
- '<span style="width: 34%; float: left; display:inline-block; overflow: hidden;">Requester</span>' +
- '<span style="width: 64%; float: right; display:inline-block; overflow: hidden;">Project</span>' +
- '</div>' +
-
- '<div style="float: right;">' +
- '<span style="width: 60px; display:inline-block; text-align: center;">Tasks</span>' +
- '<span style="width: 60px; display:inline-block; text-align: center;">Accept</span>' +
- '<span style="width: 60px; display:inline-block; text-align: center;">TV</span>' +
- '<span style="width: 60px; display:inline-block; text-align: center;">TO</span>' +
- '<span style="width: 60px; display:inline-block; text-align: center;">PANDA</span>' +
- '</div>' +
- '</div>' +
- '</div>' +
- '<div id="new_hits_"></div>' +
- '</div>' +
- '</div>' +
-
- '<br>' +
-
- //Logged HITs
- '<div id="logged_hits">' +
- '<div style="border-bottom: 3px solid; margin-bottom: 5px;">' +
- '<span style="font-size: 20px; font-weight: bold;">Logged HITs</span>' +
- '<span id="logged_hits_data" style="font-size: 11px;"></span>' +
- '<span id="log_controls" style="float: right"><button id="logg_button" style="margin-right: 0px;">Hide Logged HITs</button></span>' +
- '</div>' +
- '<div id="log_hidden" style="text-align: center; display: none;">--- LOGGED HITS HIDDEN ---</div>' +
- '<div id="log_table">' +
- '<div>' +
- '<div style="overflow: hidden; white-space: nowrap;">' +
-
- '<div style="float: left;">' +
- '<span style="width: 80px; display:inline-block;">Time</span>' +
- '</div>' +
-
- '<div style="float: left; width: calc(100% - 3500px);">' +
- '<span style="width: 25%; float: left; display:inline-block; overflow: hidden;">Requester</span>' +
- '<span style="width: 75%; float: right; display:inline-block; overflow: hidden;">Project</span>' +
-
- '</div>' +
-
- '<div style="float: right;">' +
- '<span style="width: 60px; display:inline-block; text-align: center;">Avail</span>' +
- '<span style="width: 60px; display:inline-block; text-align: center;">Accept</span>' +
- '<span style="width: 60px; display:inline-block; text-align: center;">TV</span>' +
- '<span style="width: 60px; display:inline-block; text-align: center;">TO</span>' +
- '<span style="width: 60px; display:inline-block; text-align: center;">PANDA</span>' +
- '</div>' +
- '</div>' +
- '</div>' +
- '<div id="log_hits_"></div>' +
- '</div>' +
- '</div>' +
-
- // Block List
- '<div id="bl_div" style="z-index: 99; position: fixed; width: 80%; height: 80%; left: 10%; top: 300px; margin-top: -250px; display: none;">' +
- '<div style="position: relative; width: 80%; left: 10%; border-bottom: 3px solid; padding: 2px; text-align: center;">Block List</div>' +
- '<div id="bl_items"></div>' +
- '<div style="text-align: center;">' +
- '<button id="bl_add" style="margin-right: 5px;">Add</button>' +
- '<button id="bl_close" style="margin-right: 5px;">Close</button>' +
- '<button id="bl_import" style="margin-right: 5px;">Import</button>' +
- '<button id="bl_export" style="margin-right: 0px;">Export</button>' +
- '</div>' +
- '</div>' +
-
- // Add Block List Popup
- '<div id="bl" class="add" style="z-index: 100; position: fixed; width: 520px; top: 300px; left: 50%; margin: -250px; padding: 5px; text-align: center; display: none;">' +
- '<div style="position: relative; width: 80%; left: 10%; border-bottom: 3px solid; padding: 2px; text-align: center;">Add To Block List</div>' +
-
- '<div>' +
- '<p><label>Term: </label><input id="bl_term" value="" maxlength="300"></p>' +
- '<p><label>Name: </label><input id="bl_name" value="" maxlength="300"></p>' +
- '<input id="bl_gid" value="0" type="hidden">' +
- '</div>' +
-
- '<div>' +
- '<button id="bl_add_save" style="margin-right: 5px;">Save</button>' +
- '<button id="bl_add_cancel" style="margin-right: 0px;">Cancel</button>' +
- '</div>' +
- '</div>' +
-
- // Edit Block List Popup
- '<div id="edit_bl" class="add" class="add" style="z-index: 100; position: fixed; width: 520px; top: 300px; left: 50%; margin: -250px; padding: 5px; text-align: center; display: none;">' +
- '<div style="position: relative; width: 80%; left: 10%; border-bottom: 3px solid; padding: 2px; text-align: center;">Edit Block List Item</div>' +
-
- '<div>' +
- '<p><label>Term: </label><input id="edit_bl_term" value=""disabled></p>' +
- '<p><label>Name: </label><input id="edit_bl_name" value=""></p>' +
- '</div>' +
-
- '<div>' +
- '<button id="edit_bl_save" style="margin-right: 5px;">Save</button>' +
- '<button id="edit_bl_delete" style="margin-right: 5px;">Delete</button>' +
- '<button id="edit_bl_cancel" style="margin-right: 0px;">Cancel</button>' +
- '</div>' +
- '</div>' +
-
- // Include List
- '<div id="il_div" style="z-index: 99; position: fixed; width: 80%; height: 80%; left: 10%; top: 300px; margin-top: -250px; display: none;">' +
- '<div style="position: relative; width: 80%; left: 10%; border-bottom: 3px solid; padding: 2px; text-align: center;">Include List</div>' +
- '<div id="il_items"></div>' +
- '<div style="text-align: center;">' +
- '<button id="il_add" style="margin-right: 5px;">Add</button>' +
- '<button id="il_close" style="margin-right: 5px;">Close</button>' +
- '<button id="il_import" style="margin-right: 5px;">Import</button>' +
- '<button id="il_export" style="margin-right: 0px;">Export</button>' +
- '</div>' +
- '</div>' +
-
- // Add Include List Popup
- '<div id="il" class="add" style="z-index: 100; position: fixed; width: 520px; top: 300px; left: 50%; margin: -250px; padding: 5px; text-align: center; display: none;">' +
- '<div style="position: relative; width: 80%; left: 10%; border-bottom: 3px solid; padding: 2px; text-align: center;">Add To Include List</div>' +
-
- '<div>' +
- '<p><label>Term: </label><input id="il_term" value=""></p>' +
- '<p><label>Name: </label><input id="il_name" value=""></p>' +
- '</div>' +
-
- '<div style="position: relative; width: 80%; left: 10%; border-bottom: 3px solid; padding: 2px; text-align: center;">Alerts</div>' +
-
- '<p>' +
- '<label style="margin-right: 5px; display: inline-block; border-bottom: 1px solid;">Sound: ' +
- '<select id="il_sound">' +
- '<option value="1">Sound 1</option>' +
- '<option value="2">Sound 2</option>' +
- '<option value="3">Sound 3</option>' +
- '<option value="4">Sound 4</option>' +
- '</select>' +
- '</label>' +
-
- '<label style="margin-right: 5px; display: inline-block; border-bottom: 1px solid;">Desktop Notifications' +
- '<input id="il_noti_cb" type="checkbox">' +
- '</label>' +
-
- '<label style="margin-right: 5px; display: inline-block; border-bottom: 1px solid;">Play Sound' +
- '<input id="il_sound_cb" type="checkbox">' +
- '</label>' +
-
- '<label style="margin-right: 5px; display: inline-block; border-bottom: 1px solid;">Send Pushbullet' +
- '<input id="il_push_cb" type="checkbox">' +
- '</label>' +
- '</p>' +
-
- '<div>' +
- '<button id="il_add_save" style="margin-right: 5px;">Save</button>' +
- '<button id="il_add_cancel" style="margin-right: 0px;">Cancel</button>' +
- '</div>' +
- '</div>' +
-
- // Edit Include List Popup
- '<div id="edit_il" class="add" style="z-index: 100; position: fixed; width: 520px; top: 300px; left: 50%; margin: -250px; padding: 5px; text-align: center; display: none;">' +
- '<div style="position: relative; width: 80%; left: 10%; border-bottom: 3px solid; padding: 2px; text-align: center;">Edit Include List Item</div>' +
-
- '<div>' +
- '<p><label>Term: </label><input id="edit_il_term" value="" disabled></p>' +
- '<p><label>Name: </label><input id="edit_il_name" value=""></p>' +
- '</div>' +
-
- '<div style="position: relative; width: 80%; left: 10%; border-bottom: 3px solid; padding: 2px; text-align: center;"">Alerts</div>' +
-
- '<p>' +
- '<label style="margin-right: 5px; display: inline-block; border-bottom: 1px solid;">Sound: ' +
- '<select id="edit_il_sound">' +
- '<option value="1">Sound 1</option>' +
- '<option value="2">Sound 2</option>' +
- '<option value="3">Sound 3</option>' +
- '<option value="4">Sound 4</option>' +
- '</select>' +
- '</label>' +
-
- '<label style="margin-right: 5px; display: inline-block; border-bottom: 1px solid;">Desktop Notifications' +
- '<input id="edit_il_noti_cb" type="checkbox">' +
- '</label>' +
-
- '<label style="margin-right: 5px; display: inline-block; border-bottom: 1px solid;">Play Sound' +
- '<input id="edit_il_sound_cb" type="checkbox">' +
- '</label>' +
-
- '<label style="margin-right: 0px; display: inline-block; border-bottom: 1px solid;">Send Pushbullet' +
- '<input id="edit_il_push_cb" type="checkbox">' +
- '</label>' +
- '</p>' +
-
- '<div>' +
- '<button id="edit_il_save" style="margin-right: 5px;">Save</button>' +
- '<button id="edit_il_delete" style="margin-right: 5px;">Delete</button>' +
- '<button id="edit_il_cancel" style="margin-right: 0px;">Cancel</button>' +
- '</div>' +
- '</div>' +
-
- // Advanced Settings
- '<div id="sett" class="add" style="z-index: 100; position: fixed; width: 520px; top: 300px; left: 50%; margin: -250px; padding: 5px; text-align: center; display: none;">' +
- '<div style="position: relative; width: 80%; left: 10%; border-bottom: 3px solid; padding: 2px; text-align: center;">Advanced Settings</div>' +
-
- '<div>' +
- '<p><label>Pushbullet Token: </label><input id="push" value="' + config.push + '"></p>' +
- '</div>' +
- '<div style="position: relative; width: 80%; left: 10%; border-bottom: 3px solid; padding: 2px; text-align: center;">TurkerView</div>' +
- '<div><p><label>TurkerView API Key: </label><input id="tv_api_key" value="' + ((config.tv_api_key == null || config.tv_api_key.length != 40) ? '' : config.tv_api_key) + '"></p></div>' +
- '<div><p><label><input type="checkbox" name="disable_turkerview"' + (config.disable_tv ? 'checked' : '') + '> Disable TurkerView</label></p></div>' +
- '<div><p>TurkerView is completely free (no obligation) for a month, we hope you\'ll <a href="" target="_blank">join us & try it</a>, but if not feel free to disable to stop notifications.</p></div>' +
-
- '<div style="position: relative; width: 80%; left: 10%; border-bottom: 3px solid; padding: 2px; text-align: center;">Theme</div>' +
-
- '<p>' +
- '<label style="margin-right: 5px; display: inline-block; border-bottom: 1px solid;">Theme: ' +
- '<select id="adv_theme" value="' + config.theme + '">' +
- '<option value="default">Default (Light)</option>' +
- '<option value="light">Pastel</option>' +
- '<option value="dark">Dark</option>' +
- '<option value="darker">Darker</option>' +
- '<option value="custom">Custom</option>' +
- '</select>' +
- '</label>' +
-
- '<label style="margin-right: 0px; display: inline-block; border-bottom: 1px solid;">TO Theme: ' +
- '<select id="to_theme" value="' + config.to_theme + '">' +
- '<option value="1">Default</option>' +
- '<option value="2">Column Only</option>' +
- '<option value="3">Text Only</option>' +
- '</select>' +
- '</label>' +
- '</p>' +
-
- '<p>' +
- '<label style="width: 150px; margin-right: 5px; display: inline-block; border-bottom: 1px solid; text-align: left;">Main: #' +
- '<input id="theme_main" style="width: 55px; float: right;" maxlength="6">' +
- '</label>' +
-
- '<label style="width: 150px; margin-right: 5px; display: inline-block; border-bottom: 1px solid; text-align: left;">Primary: #' +
- '<input id="theme_primary" style="width: 55px; float: right;" maxlength="6">' +
- '</label>' +
-
- '<label style="width: 150px; margin-right: 0px; display: inline-block; border-bottom: 1px solid; text-align: left;">Secondary: #' +
- '<input id="theme_secondary" style="width: 55px; float: right;" maxlength="6">' +
- '</label>' +
- '</p>' +
-
- '<p>' +
- '<label style="width: 150px; margin-right: 5px; display: inline-block; border-bottom: 1px solid; text-align: left;">Text: #' +
- '<input id="theme_text" style="width: 55px; float: right;" maxlength="6">' +
- '</label>' +
-
- '<label style="width: 150px; margin-right: 5px; display: inline-block; border-bottom: 1px solid; text-align: left;">Link: #' +
- '<input id="theme_link" style="width: 55px; float: right;" maxlength="6">' +
- '</label>' +
-
- '<label style="width: 150px; margin-right: 0px; display: inline-block; border-bottom: 1px solid; text-align: left;">Visited: #' +
- '<input id="theme_visited" style="width: 55px; float: right;" maxlength="6">' +
- '</label>' +
- '</p>' +
-
- '<div>' +
- '<button id="sett_save" style="margin-right: 5px;">Save</button>' +
- '<button id="sett_close" style="margin-right: 0px;">Close</button>' +
- '</div>' +
- '</div>'
- );
-
- // Click functions
- $('#scan_button').click(function () {
- if ($(this).text() === 'Start') {
- $(this).text('Stop');
- _scan();
- }
- else {
- $(this).text('Start');
- }
- });
-
- $('#sett_button').click(function () {
- $('#sett').toggle();
- });
-
- $('#conf_button').click(function () {
- if ($(this).text() === 'Hide Config') {
- $(this).text('Show Config');
- }
- else {
- $(this).text('Hide Config');
- }
- $('#config').toggleClass('hidden');
- });
-
- $('#logg_button').click(function () {
- _hide_log_list( $(this).text() === 'Hide Logged HITs' ? true : false );
- });
-
- $('#hits_button').click(function () {
- _hide_hit_list( $(this).text() === 'Hide New HITs' ? true : false );
- });
-
- $('#bloc_button').click(function () {
- $('#bl_div').toggle();
- });
-
- $('#bl_add').click(function () {
- $('#bl').show();
- });
-
- $('#bl_close').click(function () {
- $('#bl_div').hide();
- });
-
- $('#bl_import').click(function () {
- _import_block();
- });
-
- $('#bl_export').click(function () {
- _export_block();
- });
-
- $('#bl_add_save').click(function () {
- var obj = {
- term : $('#bl_term').val(),
- name : $('#bl_name').val() === '' ? $('#bl_term').val() : $('#bl_name').val(),
- gid : $('#bl_gid').val() === '' ? 'X' : $('#bl_gid').val()
- };
-
- _add_block(obj);
-
- if ( obj.gid != 'X' ) {
- $('.loggid_' + obj.gid ).remove();
- }
- else {
- $('.logreqid_' + obj.term ).remove();
- }
-
- $('#bl_term, #bl_name').val('');
- $('#bl').hide();
- });
-
- $('#bl_add_cancel').click(function () {
- $('#bl_term, #bl_name').val('');
- $('#bl').hide();
- });
-
- $('#edit_bl_save').click(function () {
- _update_block($(this).val());
- $('#edit_bl_term, #edit_bl_name').val('');
- $('#edit_bl').hide();
- });
-
- $('#edit_bl_delete').click(function () {
- _delete_block($(this).val());
- $('#edit_bl_term, #edit_bl_name').val('');
- $('#edit_bl').hide();
- });
-
- $('#edit_bl_cancel').click(function () {
- $('#edit_bl_term, #edit_bl_name').val('');
- $('#edit_bl').hide();
- });
-
- $('#incl_button').click(function () {
- $('#il_div').toggle();
- });
-
- $('#il_add').click(function () {
- $('#il').show();
- });
-
- $('#il_close').click(function () {
- $('#il_div').hide();
- });
-
- $('#il_import').click(function () {
- _import_include();
- });
-
- $('#il_export').click(function () {
- _export_include();
- });
-
- $('#il_add_save').click(function () {
- var obj = {
- term : $('#il_term').val().trim(),
- name : $('#il_name').val().trim() === '' ? $('#il_term').val().trim() : $('#il_name').val().trim(),
- sound : $('#il_sound').val(),
- noti_cb : $('#il_noti_cb').prop('checked'),
- sound_cb : $('#il_sound_cb').prop('checked'),
- push_cb : $('#il_push_cb').prop('checked')
- };
-
- _add_include(obj);
-
- $('#il_term, #il_name').val('');
- $('#il').hide();
- });
-
- $('#il_add_cancel').click(function () {
- $('#il_term, #il_name').val('');
- $('#il').hide();
- });
-
- $('#edit_il_save').click(function () {
- _update_include($(this).val());
- $('#edit_il_term, #edit_il_name, #edit_il_sound').val('');
- $('#edit_il_noti_cb, #edit_il_sound_cb, #edit_il_push_cb').prop('checked', false);
- $('#edit_il').hide();
- });
-
- $('#edit_il_delete').click(function () {
- _delete_include($(this).val());
- $('#edit_il_term, #edit_il_name, #edit_il_sound').val('');
- $('#edit_il_noti_cb, #edit_il_sound_cb, #edit_il_push_cb').prop('checked', false);
- $('#edit_il').hide();
- });
-
- $('#edit_il_cancel').click(function () {
- $('#edit_il_term, #edit_il_name, #edit_il_sound').val('');
- $('#edit_il_noti_cb, #edit_il_sound_cb, #edit_il_push_cb').prop('checked', false);
- $('#edit_il').hide();
- });
-
- $('.on, .off').click(function () {
- $(this).toggleClass('on off');
- _save();
- });
-
- $('#sett_save').click(function () {
-
- let original_key = config.tv_api_key;
- let new_key = $('#tv_api_key').val();
- let disable_tv = $('input[name=disable_turkerview]').is(':checked');
- config.disable_tv = disable_tv;
- _save('custom');
- _theme();
- if (original_key != new_key) {
- $('#sett').prepend(`<p class="saved-settings-alert">Settings Saved! We'll reload Forker shortly.</p>`);
- setTimeout(function() {
- window.location.reload();
- }, 1000)
- } else $('#sett').prepend(`<p class="saved-settings-alert">Settings Saved!</p>`);
- });
-
- $('#sett_close').click(function () {
- $('#sett').find('.saved-settings-alert').remove();
- $('#sett').hide();
- });
-
- $('#time').click(function () {
- $('.new').removeClass('new');
- });
-
- // Delegated click functions
- $('body').on('click', '.blockit', function () {
- _edit_block($(this).val());
- });
-
- $('body').on('click', '.includeit', function () {
- _edit_include($(this).val());
- });
-
- $('body').on('click', '.rt', function () {
- _block($(this).data('term'), $(this).data('name'), $(this).attr('id'));
- });
-
- $('body').on('click', '.it', function () {
- _includerid($(this).data('term'), $(this).data('name'), $(this).attr('id'));
- });
-
- $('body').on('click', '.pc', function () {
- _panda($(this).data('term'), $(this).data('reqname'), $(this).data('reqid'), $(this).data('title'), $(this).data('value'), $(this).data('name'), $(this))
- });
-
- $('body').on('click', '.vb', function () {
- _export_vb($(this).val());
- });
-
- $('body').on('click', '.irc', function () {
- _export_irc($(this).val());
- });
-
- $('body').on('click', '.details', function () {
- $(this).toggleClass('fa-plus-circle fa-minus-circle');
- $('.info[value="' + $(this).val() + '"]').toggle();
- });
-
- // Delegated mouseover functions
- $('body').on('mouseover', '.new', function () {
- $(this).removeClass('new');
- });
-
- // On change events
- $('#new_audio').change(function () {
- _save();
- _sound('new');
- });
-
- $('#il_sound').change(function () {
- _sound('il');
- });
-
- $('#edit_il_sound').change(function () {
- _sound('il_edit');
- });
-
- $('#type, #size, #adv_theme, #to_theme, #c_theme, :checkbox').change(function () {
- _save();
- });
-
- $('#adv_theme, #to_theme, #c_theme').change(function () {
- _theme();
- });
-
- // On input events
- $('#delay, #min_rew, #min_avail, #min_to, #alert_delay').on('input', function () {
- _save();
- });
-
- function sanitize(strings, ...values) {
- console.log( strings );
- const dirty = strings.reduce((prev, next, i) => `${prev}${next}${values[i]} || ''}`, '');
- return DomPurify.sanitize(dirty);
- }
-
- function extend(obj, src) {
- for (var key in src) {
- if (src.hasOwnProperty(key)) obj[key] = src[key];
- }
- return obj;
- }
-
- function _scan () {
- var searchqualvar
- searchqualvar = (config.qual ? 'true' : 'false');
-
-
- if ($('#scan_button').text() === 'Stop') {
- var _url = url + $('#type').val() + $('#size').val() + minrew + $('#min_rew').val() + searchqual + searchqualvar;
- //console.log( _url );
- var _scanurl = _url + '&format=json';
-
- var date = new Date(), h = date.getHours(), m = date.getMinutes(), s = date.getSeconds(), ampm = h >= 12 ? 'pm' : 'am';
- h = h % 12; h = h ? h : 12; m = m < 10 ? '0' + m : m; s = s < 10 ? '0' + s : s;
- var timeis = [h, m, s, ampm];
- console.log( _scanurl );
- $.get(_scanurl, function (data) {
- _scrape_new(data, timeis);
- }).fail(function () {
- setTimeout(function () { _scan(); }, 2500);
- });
- }
- }
-
- function _scrape_new (data, timeis) {
- var keys = [], log_keys = [], to = [], logged_in = true;
- var new_requesters = [];
- var hits = data.results;
- //Set config for allowed tags
- var config = {
- ALLOWED_TAGS: ['p', '#text']
- };
-
- for (var i = 0; i < hits.length; i ++) {
- var hit = hits[i],
- req_name = DOMPurify.sanitize(hit.requester_name,config).replace(/"/g, """ ),
- req_id = DOMPurify.sanitize(hit.requester_id,config),
- req_link = DOMPurify.sanitize(hit.requester_url.replace(/\.json/, ''),config),
- //req_link = 'https://www.mturk.com/mturk/searchbar?selectedSearchType=hitgroups&requesterId=' + hit.requester_id,
- con_link = DOMPurify.sanitize('https://www.mturk.com/mturk/contact?requesterId=' + hit.requester_id, config),
- group_id = DOMPurify.sanitize(hit.hit_set_id,config),
- prev_link = DOMPurify.sanitize(hit.project_tasks_url.replace(/\.json/, ''),config),
- //prev_link = 'https://www.mturk.com/mturk/preview?groupId=' + hit.hit_set_id,
- pand_link = DOMPurify.sanitize(hit.accept_project_task_url.replace(/\.json/, ''),config),
- //pand_link = 'https://www.mturk.com/mturk/previewandaccept?groupId=' + hit.hit_set_id,
- title = DOMPurify.sanitize(hit.title,config),
- safetitle = title.replace(/"/g, """ ),
- desc = DOMPurify.sanitize(hit.description.replace(/"/g, """ ),config),
- time = _convert_seconds(hit.assignment_duration_in_seconds),
- reward = DOMPurify.sanitize('$' + hit.monetary_reward.amount_in_dollars.toFixed(2),config),
- avail = DOMPurify.sanitize(hit.assignable_hits_count,config);
-
- var key = req_id + title + reward + group_id;
- keys.push(key);
-
- var qualif = 'None';
- var quals = hit.project_requirements;
-
-
- if (quals.length) {
-
- qualif = '';
- for (var j = 0; j < quals.length; j ++) {
- var q_comp = quals[j].comparator + ' ';
- var q_name = quals[j].qualification_type.name + ' ';
-
- var q_valu = quals[j].qualification_values;
- var q_values = '';
- for (var k = 0; k < quals.length; k ++) {
- if (quals[j].qualification_values[k]) {
- q_values += quals[j].qualification_values[k];
- q_values += k === quals.length ? ', ' : '';
- }
- }
- if ( typeof quals[j].qualification_request_url !== 'undefined' ) {
- q_values += '~!~' + quals[j].qualification_request_url;
- }
- qualif += (q_name + q_comp + q_values).trim() + '; ';
- }
- qualif = qualif.trim();
- }
-
- qualif = DOMPurify.sanitize(qualif,config);
-
- if (!hitlog[key]) {
- hitlog[key] = {
- reqname : req_name,
- reqid : req_id,
- reqlink : req_link,
- conlink : con_link,
- groupid : group_id,
- prevlink : prev_link,
- pandlink : pand_link,
- title : title,
- safetitle: safetitle,
- desc : desc,
- time : time,
- reward : reward,
- avail : avail,
- quals : qualif,
- key : key,
- tolink : 'https://turkopticon.ucsd.edu/' + req_id,
- to : { comm : 'N/A', fair : 'N/A', fast : 'N/A', pay : 'N/A' },
- tvlink : 'https://turkerview.com/requesters/' + req_id,
- tv : 'N/A'
- };
-
- if ( $.inArray( req_id, requesters ) == -1 ) {
- new_requesters.push( req_id );
- }
-
- to.push([key, req_id]);
- log_keys.push(key);
- }
- else {
- hitlog[key].avail = avail;
- }
- }
-
- var tvPromise = _getTVReviews( new_requesters );
- var toPromise = _to(keys, log_keys, logged_in, to, timeis);
-
- $.when( tvPromise, toPromise).done( function( v1, v2 ) {
- _build(keys, log_keys, timeis);
- }
- );
- }
-
- let stopTV = false;
- let tv_fail_rate = 0;
- function _getTVReviews( reqlist ) {
- var def = $.Deferred();
- if ( reqlist.length > 0 && !config.disable_tv && !stopTV){
- fetch(`https://view.turkerview.com/v1/requesters/?requester_ids=${reqlist.join()}`, {
- method: 'GET',
- cache: 'no-cache',
- headers: ViewHeaders
- }).then(response => {
- if (!response.ok) throw response;
-
- return response.json();
- }).then(json => {
-
- newreviews = json.requesters;
- $.merge( requesters, reqlist );
- turkerview = extend( turkerview, newreviews);
- def.resolve(json);
-
- }).catch(ex => {
- tv_fail_rate++;
- if (ex.statusText == 'invalidUserAuthKey') {
- stopTV = true;
- $('#TVErrorMessage').find('p').html(`<span>Your TurkerView API Key is invalid. If you haven't added it yet check the "Advanced Settings" options tab!</span><p style="margin-bottom: 0.5rem; margin-top: 0.5rem;">You can claim your free API key (or support the site with a subscription!) from your <a href="https://turkerview.com/account/api/" target="_blank">TurkerView account API dashboard.</a></p>`);
- $('#TVErrorMessage').show();
- }
- else if (ex.statusText == 'dailyLimitExceeded' || ex.statusText == 'freeTrialExpired') {
- stopTV = true;
- $('#TVErrorMessage').find('p').html(`<span>Your TurkerView API Key has hit the free quota limit, please upgrade from your <a href="https://turkerview.com/account/api/" target="_blank">TurkerView account API dashboard</a>.</span>`);
- $('#TVErrorMessage').show();
- }
-
- def.resolve( 'Empty');
- });
- }
- else {
- def.resolve( 'Empty');
- }
-
- return def.promise();
- }
-
- function _getTVHourly( reqid ) {
- var tvHourly;
- if( reqid in turkerview ) {
- tvHourly = '$' + turkerview[reqid]['wages']['average']['wage'] + "/hr";
- }
- else {
- tvHourly = '-';
- }
-
- return tvHourly;
- }
-
- function _to (keys, log_keys, logged_in, to, timeis) {
- var def = $.Deferred();
- var timeout = true;
-
- var ids = [];
-
- if (logged_in && to.length && config.to) {
- for (var i = 0; i < to.length; i++) {
- ids.push(to[i][1]);
- }
-
- $.ajax( {
- url: 'https://turkopticon.ucsd.edu/api/multi-attrs.php?ids=' + ids,
- success: function (data) {
- try {
- var to_data = JSON.parse(data);
- }
- catch(err) {
- console.log ( "Fork off TO you're drunk" );
- // malformed javascript, treat it lke TO timed out.
- def.resolve( 'Done');
- }
-
- for (i = 0; i < to.length; i++) {
- if (!to_data[to[i][1]].length && typeof to_data[to[i][1]].attrs != 'undefined') {
- hitlog[to[i][0]].to = to_data[to[i][1]].attrs;
- }
- }
-
- timeout = false;
- },
- timeout: 400
- }).always(function () {
- def.resolve( 'Done' );
- });
- }
- else {
- def.resolve( 'TO Off' );
- }
- return def.promise();
-
- }
-
- function _build (keys, log_keys, timeis) {
- var hit_html = '', log_html = '';
-
- for (var i = 0; i < keys.length; i++) {
- var hit = hitlog[keys[i]], blocked = _check_block(hit), included = _check_include(hit), remove = false, classes, tvHourly, tvScore = false;
-
- hit.tv = _getTVHourly( hit.reqid );
-
- if ( hit.tv.substring(0,3) == 'N/A' || hit.tv.substring(0,3) == '<sp' ) {
- tvScore = false;
- }
- else {
- tvScore = true;
- }
-
- rowcolor = tvScore == true ? _color_tv(hit) : 'toNone';
-
- classes = rowcolor;
-
- if (Number(config.avail) > Number(hit.avail) || Number(config.mto) > Number(hit.to.pay)) {
- classes += ' hidden';
- remove = true;
- }
-
- if (blocked) {
- classes += config.bl ? ' bl_hidden' : ' bl';
- remove = true;
- }
-
- if (included) {
- classes += ' il';
- _included(included, hit);
- }
- else {
- classes += config.nl ? ' nl_hidden' : ' nl';
- }
-
- hit_html +=
- '<div class="cont" style="margin-bottom: 2px;">' +
- '<div class="' + classes + ' " style="overflow: hidden; white-space: nowrap; margin-bottom: 2px;">' +
-
- '<div style="float: left; width: calc(100% - 330px);">' +
-
- '<span style="width: 25%; float: left; display:inline-block; overflow: hidden;">' +
- '<button data-term="' + hit.reqid + '" data-name="' + hit.reqname + '" class="rt">R</button>' +
- '<button id="'+ hit.groupid + '" data-term="' + hit.safetitle + '" data-name="' + hit.safetitle + '" class="rt">T</button>' +
- '<button data-term="' + hit.reqid + '" data-name="' + hit.reqname + '" class="it">I</button>' +
- '<a href="' + hit.reqlink + '">' + hit.reqname + '</a>' +
- '</span>' +
-
- '<span style="width: 75%; float: right; display:inline-block; overflow: hidden;">' +
- '<button value="' + hit.key + '" class="vb">vB</button>' +
- '<button value="' + hit.key + '" class="irc">IRC</button>' +
- '<a href="' + hit.prevlink + '">' + hit.safetitle + '</a>' +
- '</span>' +
-
- '</div>' +
-
- '<div style="float: right;">' +
-
- '<span style="width: 60px; display:inline-block; text-align: center;">' +
- hit.avail +
- '</span>' +
-
- '<span style="width: 60px; display:inline-block; text-align: center;">' +
- '<a href="' + hit.pandlink + '">' + hit.reward + '</a>' +
- '</span>' +
-
- '<span class="to" style="width: 60px; display:inline-block; text-align: center;">' +
- '<a href="' + hit.tvlink + '">' + hit.tv + '</a>' +
- '</span>' +
-
- '<span class="to" style="width: 60px; display:inline-block; text-align: center;">' +
- '<a href="' + hit.tolink + '">' + hit.to.pay + '</a>' +
- '</span>' +
-
- '<span style="width: 60px; display:inline-block; text-align: center;">' +
- '<button data-term="' + hit.groupid + '" data-reqid="' + hit.reqid + '" data-reqname="' + hit.reqname.replace(/"/g, """ ) + '" data-title="' + hit.safetitle + '" data-value="' + hit.reward.replace(/\$/g, '') + '" data-name="panda" class="pc">P</button>' +
- '<button data-term="' + hit.groupid + '" data-reqid="' + hit.reqid + '" data-reqname="' + hit.reqname.replace(/"/g, """ ) + '" data-title="' + hit.safetitle + '" data-value="' + hit.reward.replace(/\$/g, '') + '" data-name="once" class="pc">O</button>' +
- '</span>' +
-
- '</div>' +
- '</div>' +
- '</div>'
- ;
-
- if (remove) {
- var index = log_keys.indexOf(keys[i]);
-
- if (index > -1) {
- log_keys.splice(index, 1);
- }
- }
- }
-
- if (log_keys.length) {
- for (var j = 0; j < log_keys.length; j ++) {
- var hit_log = hitlog[log_keys[j]], included_log = _check_include(hit_log), rowcolor, classes_log, tvHourly;
-
- rowcolor = hit_log.tv != 'N/A' ? _color_tv(hit_log) : 'toNone';
-
- classes_log = rowcolor;
-
- if (included_log) {
- classes_log += ' il';
- }
- else {
- classes_log += config.nl ? ' nl_hidden' : ' nl';
- }
-
- var quals = hit_log.quals.split(';');
- var qualif = '';
-
- for (var k = 0; k < quals.length; k ++) {
- if (quals[k] !== '') {
- if( quals[k].indexOf('~!~') != -1 ) {
- var temp = quals[k].split('~!~');
- quals[k] = temp[0];
- if (temp[1].indexOf('request') == -1 ) {
- //Qual test
- quals[k] += '<form action="' +temp[1] +'" method="get" style=" display:inline!important;"><button>Take Test</button></form>';
- }
- else {
- //Request Qual
- //quals[k] += '<form action="' +temp[1] +'" method="post"><button>Request</button></form>';
- }
- }
- qualif += '<li style="padding: 2px;">' + quals[k] + '</li>';
- }
- }
-
-
-
- log_html +=
- '<div class="cont loggid_' + hit_log.groupid +' logreqid_' + hit_log.reqid + '" style="margin-bottom: 2px;">' +
- '<div class="' + classes_log + '" style="overflow: hidden; white-space: nowrap;">' +
-
- '<div style="float: left;">' +
- '<span style="width: 80px; display:inline-block;">' +
- '<button class="fa fa-plus-circle fa-2 details" aria-hidden="true" value="' + hit_log.key + '" style="background-color: transparent; border: 0px; padding: 1px;"></button>' +
- timeis[0] + ':' + timeis[1] + timeis[3] + '</span>' +
- '</div>' +
-
- '<div style="float: left; width: calc(100% - 410px);">' +
-
- '<span style="width: 25%; float: left; display:inline-block; overflow: hidden;">' +
- '<button data-term="' + hit_log.reqid + '" data-name="' + hit_log.reqname + '" class="rt">R</button>' +
- '<button id="'+ hit_log.groupid + '" data-term="' + hit_log.safetitle + '" data-name="' + hit_log.safetitle + '" class="rt">T</button>' +
- '<button data-term="' + hit_log.reqid + '" data-name="' + hit_log.reqname + '" class="it">I</button>' +
- '<a href="' + hit_log.reqlink + '">' + hit_log.reqname + '</a>' +
- '</span>' +
-
- '<span style="width: 75%; float: right; display:inline-block; overflow: hidden;">' +
- '<button value="' + hit_log.key + '" class="vb">vB</button>' +
- '<button value="' + hit_log.key + '" class="irc">IRC</button>' +
- '<a href="' + hit_log.prevlink + '">' + hit_log.safetitle + '</a>' +
- '</span>' +
-
- '</div>' +
-
- '<div style="float: right;">' +
-
- '<span style="width: 60px; display:inline-block; text-align: center;">' +
- hit_log.avail +
- '</span>' +
-
- '<span style="width: 60px; display: inline-block; text-align: center;">' +
- '<a href="' + hit_log.pandlink + '">' + hit_log.reward + '</a>' +
- '</span>' +
-
- '<span class="to" style="width: 60px; display:inline-block; text-align: center;">' +
- '<a href="' + hit_log.tvlink + '">' + hit_log.tv + '</a>' +
- '</span>' +
-
-
- '<span class="to" style="width: 60px; display:inline-block; text-align: center;">' +
- '<a href="' + hit_log.tolink + '">' + hit_log.to.pay + '</a>' +
- '</span>' +
-
- '<span style="width: 60px; display:inline-block; text-align: center;">' +
- '<button data-term="' + hit_log.groupid + '" data-reqid="' + hit_log.reqid + '" data-reqname="' + hit_log.reqname.replace(/"/g, """ ) + '" data-title="' + hit_log.safetitle + '" data-value="' + hit_log.reward.replace(/\$/g, '') + '" data-name="panda" class="pc">P</button>' +
- '<button data-term="' + hit_log.groupid + '" data-reqid="' + hit_log.reqid + '" data-reqname="' + hit_log.reqname.replace(/"/g, """ ) + '" data-title="' + hit_log.safetitle + '" data-value="' + hit_log.reward.replace(/\$/g, '') + '" data-name="once" class="pc">O</button>' +
- '</span>' +
-
- '</div>' +
- '</div>'+
-
- '<div class="info ' + rowcolor + '" value="' + hit_log.key + '" style="overflow: hidden; display: none; font-size: 11px;">' +
-
- '<div style="border-bottom: 1px solid #000000;"></div>' +
-
- '<span style="width: 33%; float: left; display:inline-block; padding: 5px;">' +
- '<span style="text-decoration: underline;">Description</span>' +
- '<div style="padding: 2px;">' + hit_log.desc +'</div>' +
- '<span style="text-decoration: underline;">Time</span>' +
- '<div style="padding: 2px;">' + hit_log.time +'</div>' +
- '</span>' +
-
- '<span style="width: 33%; float: left; display:inline-block; padding: 5px;">' +
- '<span style="text-decoration: underline;">Qualifications</span>' +
- qualif +
- '</span>' +
-
- '<span style="width: calc(34% - 30px); float: right; display:inline-block; padding: 5px;">' +
- '<span style="text-decoration: underline;">Turkopticon</span>' +
- '<br>' +
- '<span style="width: 70px; display:inline-block; padding: 2px;">Pay : ' + hit_log.to.pay +'</span>' +
- '<span style="width: 70px; display:inline-block; padding: 2px;">Fair : ' + hit_log.to.fair +'</span>' +
- '<br>' +
- '<span style="width: 70px; display:inline-block; padding: 2px;">Comm : ' + hit_log.to.comm +'</span>' +
- '<span style="width: 70px; display:inline-block; padding: 2px;">Fast : ' + hit_log.to.fast +'</span>' +
- '</span>' +
-
- '</div>' +
- '</div>';
-
- logged ++;
- }
- if (config.new) {
- _sound('new');
- }
- }
- $('#new_hits_').html(hit_html);
- $('#log_hits_').prepend(log_html);
-
- searches ++;
- var hits_data = '<span> ' + timeis[0] + ':' + timeis[1] + ':' + timeis[2] + timeis[3] + ' Scanned HITs: ' + keys.length + '</span><span style="float: right;">' + tv_fail_rate + '/' + searches + '</span>';
- var logged_hits_data = '<span style="float: right;">' + logged + '</span>';
-
- $('#hits_data').html(hits_data);
- $('#logged_hits_data').html(logged_hits_data);
-
- if ($('#scan_button').text() === 'Stop') {
- setTimeout(function () {
- _scan();
- }, $('#delay').val() * 1000);
- }
- }
-
- function _sound (sound) {
- if (sound === 'new') { $('#audio_' + config.newaudio) [0].play(); }
- if (sound === 'include') { $('#audio_' + config.newaudio) [0].play(); }
- if (sound === 'il') { $('#audio_' + $('#il_sound').val()) [0].play(); }
- if (sound === 'il_edit') { $('#audio_' + $('#edit_il_sound').val()) [0].play(); }
- }
-
- function _check_block (hit) {
- for (var key in blocklist) {
- var obj = blocklist[key];
- if (obj.term.toLowerCase() === hit.reqname.toLowerCase() || obj.term.toLowerCase() === hit.title.toLowerCase() || obj.term.toLowerCase() === hit.reqid.toLowerCase() || obj.term.toLowerCase() === hit.groupid.toLowerCase()) {
- return obj;
- }
- }
- }
-
- function _check_include (hit) {
- for (var key in includelist) {
- var obj = includelist[key];
- if (obj.term.toLowerCase() === hit.reqname.toLowerCase() || obj.term.toLowerCase() === hit.title.toLowerCase() || obj.term.toLowerCase() === hit.reqid.toLowerCase() || obj.term.toLowerCase() === hit.groupid.toLowerCase()) {
- return obj;
- }
- }
- }
-
- function _included (obj, hit) {
- var check = noti_delay.indexOf(hit.key) !== -1;
- var pushcheck = push_delay.indexOf(hit.key) !== -1;
-
- if (!check) {
- noti_delay.unshift(hit.key);
- setTimeout(function () { noti_delay.pop(); }, config.alert * 1000);
- }
- if (obj.noti_cb && !check) {
- Notification.requestPermission();
- var n = new Notification(hit.reqname + ' | ' + hit.reward, {
- icon : 'http://nopurpose.org/stuff/avatars/Lj21396.gif',
- body : hit.title,
- });
- setTimeout(n.close.bind(n), 5000);
-
- n.onclick = function(e) {
- e.preventDefault();
- window.open(hit.prevlink, '_blank');
- };
-
- }
- if (obj.sound_cb && !check) {
- if ( !config.tts ) {
- $('#audio_' + obj.sound)[0].play();
- }
- else {
- //Console.log("BOOM, TTS");
- slothbearsTTS(obj);
- }
- }
- if (obj.push_cb && !pushcheck && config.pb) {
- push_delay.unshift(hit.key);
- setTimeout(function () { push_delay.pop(); }, 900000);
-
- var push = {};
-
- push['type'] = 'note';
- push['title'] = 'HIT Finder';
- push['body'] = '[' + hit.reqname + ']\n[' + hit.safetitle + ']\n[' + hit.reward + ']\n[' + hit.prevlink + ']';
-
- $.ajax({
- type : 'POST',
- headers : {'Authorization': 'Bearer ' + config.push},
- url : 'https://api.pushbullet.com/v2/pushes',
- data : push
- });
-
- }
- }
-
- function _color_tv(hit) {
- var tvHourly = hit.tv.replace(/\$/g, '').replace(/\/hr/g, '');
-
- if (tvHourly == '-') return 'toNone';
-
- if (config.theme == "light") {
- if (tvHourly >= 10.00) { return 'tvHigh'; }
- else if (tvHourly >= 7.25) { return 'tvFair'; }
- else { return 'tvLow'; }
- }
- else {
- if (tvHourly >= 10.00) { return 'toHigh'; }
- else if (tvHourly >= 7.25) { return 'toAverage'; }
- else { return 'toLow'; }
-
- }
- }
-
- function _color_to (hit) {
- var to = hit.to.pay;
-
- if (config.theme == "light") {
- if (to > 4) { return 'tvHigh'; }
- else if (to > 2.5) { return 'tvFair'; }
- else if (to > 0) { return 'tvLow'; }
- else { return 'tvNone'; }
- }
- else {
- if (to > 4) { return 'toHigh'; }
- else if (to > 3) { return 'toGood'; }
- else if (to > 2.25) { return 'toAverage'; }
- else if (to > 1.25) { return 'toLow'; }
- else if (to > 0) { return 'toPoor'; }
- else { return 'toNone'; }
-
- }
- }
-
- function _convert_seconds (seconds) {
- seconds = Number(seconds);
- var h = Math.floor(seconds / 3600);
- var m = Math.floor(seconds % 3600 / 60);
- var s = Math.floor(seconds % 3600 % 60);
- var time = '';
- if (h > 0) { time += h + ' hour(s) '; }
- if (m > 0) { time += m + ' minutes(s) '; }
- if (s > 0) { time += s + ' seconds(s)'; }
- return time;
- }
-
- function _block (term, name, gid) {
- $('#bl_term') .val(term);
- $('#bl_name') .val(name);
- $('#bl_gid').val(gid);
- $('#bl') .show();
- }
-
- function _includerid( term, name, gid ) {
- $('#il_term') .val(term);
- $('#il_name') .val(name);
- $('#il') .show();
- }
-
- function _panda(term, reqname, reqid, title, value, name, button) {
- var hitData = {
- hitTitle: title,
- requesterName: reqname,
- requesterId: reqid,
- hitValue: value
- }
-
- var once = name == "panda" ? false : true;
-
- PandaCrazy.online().then (
- function(successResp) {
- PandaCrazy.addJob( term, once, hitData );
- button.addClass("clicked")
- },
- function(failedResp) {
- alert( "Panda Crazy doesn't appear to be running. Please double check if it's being run on the same browser profile and try again");
- }
- );
- //console.log ( running );
- }
-
-
- function _add_block (obj) {
- if (!blocklist[obj.term]) {
- blocklist[obj.term] = obj;
- _init_lists();
- }
- }
-
- function _edit_block (term) {
- var obj = blocklist[term];
- $('#edit_bl_term') .val(obj.term) .text(obj.term);
- $('#edit_bl_name') .val(obj.name);
- $('#edit_bl_save') .val(obj.term);
- $('#edit_bl_delete') .val(obj.term);
- $('#edit_bl') .show();
- }
-
- function _update_block (block) {
- var obj = blocklist[block];
- obj.name = $('#edit_bl_name').val();
- _init_lists();
- }
-
- function _delete_block (block) {
- delete blocklist[block];
- _init_lists();
- }
-
- function _add_include (obj) {
- if (!includelist[obj.term]) {
- includelist[obj.term] = obj;
- _init_lists();
- }
- }
-
- function _edit_include (term) {
- var obj = includelist[term];
-
- $('#edit_il_term') .val(obj.term) .text(obj.term);
- $('#edit_il_name') .val(obj.name);
- $('#edit_il_sound') .val(obj.sound);
-
- $('#edit_il_noti_cb') .prop('checked', obj.noti_cb);
- $('#edit_il_sound_cb') .prop('checked', obj.sound_cb);
- $('#edit_il_push_cb') .prop('checked', obj.push_cb);
-
- $('#edit_il_save') .val(obj.term);
- $('#edit_il_delete') .val(obj.term);
-
- $('#edit_il').show();
- }
-
- function _update_include (term) {
- var obj = includelist[term];
- obj.name = $('#edit_il_name') .val().trim();
- obj.sound = $('#edit_il_sound') .val().trim();
- obj.noti_cb = $('#edit_il_noti_cb') .prop('checked');
- obj.sound_cb = $('#edit_il_sound_cb') .prop('checked');
- obj.push_cb = $('#edit_il_push_cb') .prop('checked');
- _init_lists();
- }
-
- function _delete_include (term) {
- delete includelist[term];
- _init_lists();
- }
-
- function _hide_hit_list( hide ) {
- if (hide) {
- $("#hits_button").text('Show New HITs');
- $('#hits_table').hide();
- $('#hits_hidden').show();
- config.h_hidden = '1';
- }
- else {
- $("#hits_button").text('Hide New HITs');
- $('#hits_table').show();
- $('#hits_hidden').hide();
- config.h_hidden = '0';
- }
-
- _save( 'showhide' );
- }
-
- function _hide_log_list( hide ) {
- if (hide) {
- $("#logg_button").text('Show Logged HITs');
- $('#log_table').hide();
- $('#log_hidden').show();
- config.l_hidden = '1';
- }
- else {
- $("#logg_button").text('Hide Logged HITs');
- $('#log_table').show();
- $('#log_hidden').hide();
- config.l_hidden = '0';
- }
-
- _save( 'showhide' );
- }
-
- function _init_lists () {
- var bl_sort = [], il_sort = [], bl_html = '', il_html = '';
-
- for (var bl_key in blocklist) {
- bl_sort.push([bl_key, blocklist[bl_key].name]);
- }
-
- bl_sort.sort(function (a, b) {
- if (a[1].toLowerCase() < b[1].toLowerCase()) return -1;
- if (a[1].toLowerCase() > b[1].toLowerCase()) return 1;
- return 0;
- });
-
- for (var i = 0; i < bl_sort.length; i ++) {
- var bl_obj = blocklist[bl_sort[i][0]];
- bl_html += '<button class="blockit" style="margin: 2px;" value="' + bl_obj.term + '" title="' + bl_obj.term + '">' + bl_obj.name + '</button>';
- }
-
- for (var il_key in includelist) {
- il_sort.push([il_key, includelist[il_key].name]);
- }
-
- il_sort.sort(function (a, b) {
- if (a[1].toLowerCase() < b[1].toLowerCase()) return -1;
- if (a[1].toLowerCase() > b[1].toLowerCase()) return 1;
- return 0;
- });
-
- for (var j = 0; j < il_sort.length; j ++) {
- var il_obj = includelist[il_sort[j][0]];
- il_html += '<button class="includeit" style="margin: 2px;" value="' + il_obj.term + '" title="' + il_obj.term + '">' + il_obj.name + '</button>';
- }
-
- $('#bl_items') .html(bl_html);
- $('#il_items') .html(il_html);
- _save('init');
- }
-
- function _import_block () {
- var import_bl = prompt(
- 'Block List Import\n\n' +
- 'You can import from HIT Finder or HIT Scraper.\n\n' +
- 'This will not delete your current block list, only add to it.\n\n' +
- 'Please enter your block list here.',
- ''
- );
-
- if (import_bl) {
- var json = _json_validator(import_bl);
-
- if (json) {
- var _bl_obj = JSON.parse(import_bl);
- for (var key in _bl_obj) {
- if (_bl_obj[key].hasOwnProperty('term') && _bl_obj[key].hasOwnProperty('name') && !_bl_obj[key].hasOwnProperty('sound')) {
- if (!blocklist[key]) {
- blocklist[key] = {
- term : _bl_obj[key].term,
- name : _bl_obj[key].name
- };
- }
- }
- else {
- alert('An error occured while importing.\n\n Please check if you have a valid import and try again.');
- break;
- }
- }
- _init_lists();
- }
- else if (import_bl.match(/^/)) {
- var _bl_arr = import_bl.trim().split('^');
- for (var i = 0; i < _bl_arr.length; i ++) {
- if (!blocklist[_bl_arr[i]]) {
- blocklist[_bl_arr[i]] = {
- term : _bl_arr[i],
- name : _bl_arr[i]
- };
- }
- }
- _init_lists();
- }
- }
- else {
- alert('An error occured while importing.\n\n Please check if you have a valid import and try again.');
- }
- }
-
- function _export_block () {
- GM_setClipboard(localStorage.getItem('_finder_bl'));
- alert('Your block list has been copied to your clipboard.');
- }
-
- function _import_include () {
- var import_il = prompt(
- 'Include List Import\n\n' +
- 'You can import from HIT Finder or HIT Scraper.\n\n' +
- 'This will not delete your current include list, only add to it.\n\n' +
- 'Please enter your include list here.',
- ''
- );
-
- if (import_il) {
- var json = _json_validator(import_il);
-
- if (json) {
- var _il_obj = JSON.parse(import_il);
-
- for (var key in _il_obj) {
- if (_il_obj[key].hasOwnProperty('term') && _il_obj[key].hasOwnProperty('name') && _il_obj[key].hasOwnProperty('sound')) {
- if (!includelist[key]) {
- includelist[key] = {
- term : _il_obj[key].term,
- name : _il_obj[key].name,
- sound : _il_obj[key].sound,
- noti_cb : _il_obj[key].noti_cb,
- sound_cb : _il_obj[key].sound_cb,
- push_cb : _il_obj[key].push_cb
- };
- }
- }
- else {
- alert('An error occured while importing.\n\n Please check that you have a valid import and try again.');
- break;
- }
- }
- _init_lists();
- }
- else if (import_il.match(/^/)) {
- var _il_arr = import_il.split('^');
-
- for (var i = 0; i < _il_arr.length; i ++) {
- if (!includelist[_il_arr[i]]) {
- includelist[_il_arr[i]] = {
- term : _il_arr[i],
- name : _il_arr[i],
- sound : '1',
- noti_cb : true,
- sound_cb : true,
- push_cb : false
- };
- }
- }
- _init_lists();
- }
- }
- else {
- alert('An error occured while importing.\n\n Please check that you have a valid import and try again.');
- }
- }
-
- function _export_include () {
- GM_setClipboard(localStorage.getItem('_finder_il'));
- alert('Your include list has been copied to your clipboard.');
- }
-
- function _export_vb (key) {
- var hit = hitlog[key];
-
- var pay = hit.to.pay, _pay = '#B30000';
- if (pay > 3.99) { _pay = '#00B300'; }
- else if (pay > 2.99) { _pay = '#B3B300'; }
- else if (pay > 1.99) { _pay = '#B37400'; }
-
- var fair = hit.to.fair, _fair = '#B30000';
- if (fair > 3.99) { _fair = '#00B300'; }
- else if (fair > 2.99) { _fair = '#B3B300'; }
- else if (fair > 1.99) { _fair = '#B37400'; }
-
- var comm = hit.to.comm, _comm = '#B30000';
- if (comm > 3.99) { _comm = '#00B300'; }
- else if (comm > 2.99) { _comm = '#B3B300'; }
- else if (comm > 1.99) { _comm = '#B37400'; }
-
- var fast = hit.to.fast, _fast = '#B30000';
- if (fast > 3.99) { _fast = '#00B300'; }
- else if (fast > 2.99) { _fast = '#B3B300'; }
- else if (fast > 1.99) { _fast = '#B37400'; }
-
- var tv = hit.tv.replace(/\$/g, ''), _tvhourly = '#B30000';
- if ( tv != 'N/A' ) {
- if ( tv >= 10 ) { _tvhourly = '#00B300'; }
- else if ( tv >= 7.25 ) { _tvhourly = '#B3B300'; }
- tv = '$' + tv + '/hr';
- }
-
- var quals = hit.quals.split(';');
- var qualif = '';
-
- for (var k = 0; k < quals.length; k ++) {
- if (quals[k] !== '') {
- if( quals[k].indexOf('~!~') != -1 ) {
- var temp = quals[k].split('~!~');
- quals[k] = temp[0];
- if (temp[1].indexOf('request') == -1 ) {
- //Qual test
- quals[k] += '[URL=' +temp[1] +']Take Test[/URL]';
- }
- else {
- //Request Qual
- //quals[k] += '<form action="' +temp[1] +'" method="post"><button>Request</button></form>';
- }
- }
- qualif += quals[k] + ';';
- }
- }
-
- var exportcode = '[table][tr][td]'+
- '[b]Title:[/b] [URL=' + pandaurl + hit.prevlink + ']' + hit.safetitle + '[/URL] | [URL=' + pandaurl + hit.pandlink + ']PANDA[/URL]\n' +
- '[b]Requester:[/b] [URL=' + pandaurl + hit.reqlink + ']' + hit.reqname + '[/URL] [' + hit.reqid + '] ([URL=' + hit.tvlink +']Req TV[/URL]): [B][COLOR=' + _tvhourly + ']' + tv + '[/COLOR][/B]\n' +
- '([URL='+hit.tolink+']TO[/URL]):'+
- '[b] \[Pay: [COLOR=' + _pay + ']' + pay + '[/COLOR]\][/b]'+
- '[b] \[Fair: [COLOR=' + _fair + ']' + fair + '[/COLOR]\][/b]' +
- '[b] \[Comm: [COLOR=' + _comm +']' + comm + '[/COLOR]\][/b]' +
- '[b] \[Fast: [COLOR=' + _fast + ']' + fast + '[/COLOR]\][/b]\n' +
- '[b]Description:[/b] ' + hit.desc + '\n' +
- '[b]Time:[/b] ' + hit.time + '\n' +
- '[b]HITs Available:[/b] ' + hit.avail + '\n' +
- '[b]Reward:[/b] [COLOR=green][b] ' + hit.reward + '[/b][/COLOR]\n' +
- '[b]Qualifications:[/b] ' + qualif + '\n' +
- '[/td][/tr][/table]';
-
- GM_setClipboard(exportcode);
- alert('Forum export has been copied to your clipboard.');
- }
-
- function _export_irc (key) {
- var hit = hitlog[key];
-
- $.get('https://ns4t.net/yourls-api.php?action=bulkshortener&title=MTurk&signature=39f6cf4959&urls[]=https://worker.mturk.com' + hit.prevlink + '&urls[]=https://worker.mturk.com' + hit.pandlink, function (data) {
- var urls = data.split(';'),
- preview = urls[0],
- panda = urls[1];
-
- var exportcode = 'Req: ' + hit.reqname + ' ■ Title: ' + hit.safetitle + ' ■ Reward: ' + hit.reward;
- exportcode += preview !== panda ? ' ■ Prev: ' + preview + ' ■ PandA: '+ panda : ' ■ Search: ' + preview;
- exportcode += ' ■ TO: (Pay: ' + hit.to.pay + ') (Fair: ' + hit.to.fair + ') (Comm: ' + hit.to.comm + ') (Fast: ' + hit.to.fast + ')';
-
- GM_setClipboard(exportcode);
- alert('IRC export has been copied to your clipboard.');
-
- }).fail(function () {
- alert('Failed to shorten links.');
- });
- }
-
- function _json_validator (data) {
- try {
- JSON.parse(data);
- return true;
- }
- catch (e) {
- return false;
- }
- }
-
- function _save (type) {
- if (type !== 'init' && type !== 'custom') {
- config.delay = $('#delay') .val();
- config.rew = $('#min_rew') .val();
- config.avail = $('#min_avail') .val();
- config.mto = $('#min_to') .val();
- config.alert = $('#alert_delay') .val();
- config.type = $('#type') .val();
- config.size = $('#size') .val();
- config.newaudio = $('#new_audio') .val();
- config.theme = $('#adv_theme') .val();
- config.to_theme = $('#to_theme') .val();
-
- config.new = $('#new_sound') .prop('checked');
- config.pb = $('#pb') .prop('checked');
- config.tts = $('#tts') .prop('checked');
- config.to = $('#to') .prop('checked');
- config.qual = $('#qual') .prop('checked');
- config.nl = $('#nl_hide') .prop('checked');
- config.bl = $('#bl_hide') .prop('checked');
- config.m = $('#m_hide') .prop('checked');
- console.log($('#push').val());
-
- }
- if (type === 'custom' && $('#adv_theme').val() === 'custom') {
- config.custom = {
- main : $('#theme_main') .val(),
- primary : $('#theme_primary') .val(),
- secondary : $('#theme_secondary') .val(),
- text : $('#theme_text') .val(),
- link : $('#theme_link') .val(),
- visited : $('#theme_visited') .val(),
- prop : false
- };
- themes.custom = config.custom;
- }
- config.push = $('#push').val();
- config.tv_api_key = $('#tv_api_key').val();
-
- localStorage.setItem('_finder', JSON.stringify(config));
- localStorage.setItem('_finder_bl', JSON.stringify(blocklist));
- localStorage.setItem('_finder_il', JSON.stringify(includelist));
-
- if (config.nl) { $('.nl').toggleClass('nl nl_hidden'); }
- else { $('.nl_hidden').toggleClass('nl nl_hidden'); }
-
- if (config.bl) { $('.bl').toggleClass('bl bl_hidden'); }
- else { $('.bl_hidden').toggleClass('bl bl_hidden'); }
-
- if (config.m) { $('.m').toggleClass('m m_hidden'); }
- else { $('.m_hidden').toggleClass('m m_hidden'); }
- }
-
- function _theme () {
- var theme = themes[config.theme];
-
- $('#theme_main') .val(theme.main) .prop('disabled', theme.prop);
- $('#theme_primary') .val(theme.primary) .prop('disabled', theme.prop);
- $('#theme_secondary') .val(theme.secondary) .prop('disabled', theme.prop);
- $('#theme_text') .val(theme.text) .prop('disabled', theme.prop);
- $('#theme_link') .val(theme.link) .prop('disabled', theme.prop);
- $('#theme_visited') .val(theme.visited) .prop('disabled', theme.prop);
- _write_theme();
- }
-
- function _write_theme () {
- var css = _to_theme(), theme = themes[config.theme];
-
- css +=
- 'html {color: #' + theme.text + '; background-color: #' + theme.main + '; line-height: 1.5; font-family: "Roboto", sans-serif; font-size: 15px; font-weight: normal;}' +
- 'body {margin: 0px;}' +
- '#menubar { background-color: #' + theme.menu + '; margin: 0px; padding: 3px; height:30px; color: #' + theme.menutext + ' }' +
- '#latest_hits { margin: 5px; }' +
- '#logged_hits { margin: 5px; }' +
- '#config { background-color: #' + theme.primary + '; border: 2px #' + theme.text + ' solid; padding: 2px;}' +
-
- '#bl_items, #il_items {background-color: #'+theme.main+'; height: calc(100% - 64px); overflow-y: scroll;}' +
- '#bl_div, #il_div {background-color: #'+theme.primary+'; border: 2px solid #'+theme.secondary+';}' +
-
- '.add {background-color: #'+theme.primary+'; border: 2px solid #'+theme.secondary+';}' +
-
- '.bl {border: 2px solid #FF0000;}' +
- '.il {border: 2px solid #009900;}' +
- '.hidden, .nl_hidden, .bl_hidden, .m_hidden {display: none;}' +
- 'button:focus {outline: none !important;}';
-
- if (config.theme == 'light' ) {
- css +=
- '.tvHigh {background-color: rgba(0,128,0,0.3); }' +
- '.tvFair {background-color: rgba(255,165, 0, 0.3);}' +
- '.tvLow {background-color: rgba(255,0,0,0.3); }' +
- '.tvNone {background-color: rgba(128,128,128, 0.3); }'
- }
-
- $('#css').html(css);
- }
-
- function _to_theme () {
- var to, theme = themes[config.theme], color = '';
- console.log(config.to_theme);
- if (config.theme === 'default') {
- color = 'd9d9d9';
- }
- else {
- color = '262626';
- }
-
- switch (config.to_theme) {
- case '1':
- to =
- 'td {font-weight: bold;}' +
- '.cont, .hit, .details {color: #000000;}' +
- '.toHigh {background-color: #33cc59;}' +
- '.toGood {background-color: #a6cc33;}' +
- '.toAverage {background-color: #cccc33;}' +
- '.toLow {background-color: #cca633;}' +
- '.toPoor {background-color: #cc3333;}' +
- '.toNone {background-color: #cccccc;}' +
- '.rt, .it, .pc {width: 20px; height: 20px; background-color: transparent; margin: 1px; border: 1px solid #000000; font-size: 80%; padding: 1px;}' +
- '.vb, .irc {width: 25px; height: 20px; background-color: transparent; margin: 1px; border: 1px solid #000000; font-size: 80%; padding: 1px;}' +
- '.clicked {background-color:grey;}';
- ;
- return to;
- case '2':
- to =
- 'a {color: #'+theme.link+';}' +
- 'a:visited {color: #'+theme.visited+';}' +
- 'tbody td {color: #'+theme.text+';}' +
- '.to a {color: #000000;}' +
-
- '.cont, .details {color: #'+theme.text+';}' +
- '.toHigh {background-color: #'+color+';}' +
- '.toGood {background-color: #'+color+';}' +
- '.toAverage {background-color: #'+color+';}' +
- '.toLow {background-color: #'+color+';}' +
- '.toPoor {background-color: #'+color+';}' +
- '.toNone {background-color: #'+color+';}' +
-
- '.toHigh .to {background-color: #33cc59;}' +
- '.toGood .to {background-color: #a6cc33;}' +
- '.toAverage .to {background-color: #cccc33;}' +
- '.toLow .to {background-color: #cca633;}' +
- '.toPoor .to {background-color: #cc3333;}' +
- '.toNone .to {background-color: #cccccc;}' +
- '.rt, .pc {width: 20px; height: 20px; color: #'+theme.text+'; background-color: transparent; margin: 1px; border: 1px solid #'+theme.text+'; font-size: 80%; padding: 1px;}' +
- '.vb, .irc {width: 25px; height: 20px; color: #'+theme.text+'; background-color: transparent; margin: 1px; border: 1px solid #'+theme.text+'; font-size: 80%; padding: 1px;}' +
- '.clicked {background-color:grey;}';
- ;
- return to;
- case '3':
- to =
- 'a {color: #'+theme.link+';}' +
- 'a:visited {color: #'+theme.visited+';}' +
- 'tbody td {color: #'+theme.text+';}' +
-
- '.cont, .details {color: #'+theme.text+';}' +
- '.toHigh {background-color: #'+color+';}' +
- '.toGood {background-color: #'+color+';}' +
- '.toAverage {background-color: #'+color+';}' +
- '.toLow {background-color: #'+color+';}' +
- '.toPoor {background-color: #'+color+';}' +
- '.toNone {background-color: #'+color+';}' +
-
- '.toHigh .to a {color: #33cc59;}' +
- '.toGood .to a {color: #a6cc33;}' +
- '.toAverage .to a {color: #cccc33;}' +
- '.toLow .to a {color: #cca633;}' +
- '.toPoor .to a {color: #cc3333;}' +
- '.toNone .to a {color: #cccccc;}' +
- '.rt, .pc {width: 20px; height: 20px; color: #'+theme.text+'; background-color: transparent; margin: 1px; border: 1px solid #'+theme.text+'; font-size: 80%; padding: 1px;}' +
- '.vb, .irc {width: 25px; height: 20px; color: #'+theme.text+'; background-color: transparent; margin: 1px; border: 1px solid #'+theme.text+'; font-size: 80%; padding: 1px;}' +
- '.clicked {background-color:grey;}';
- ;
- return to;
- }
- }
-
- $('#type option[value="' + config.type + '"]') .prop('selected', true);
- $('#size option[value="' + config.size + '"]') .prop('selected', true);
- $('#new_audio option[value="' + config.newaudio + '"]') .prop('selected', true);
- $('#adv_theme option[value="' + config.theme + '"]') .prop('selected', true);
- $('#to_theme option[value="' + config.to_theme + '"]') .prop('selected', true);
-
- _theme();
- _init_lists();
- _hide_hit_list( config.h_hidden == '1' ? true : false );
- _hide_log_list( config.l_hidden == '1' ? true : false );