HIT Forker

Monitors mturk.com for HITs

目前為 2018-03-20 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name HIT Forker
  3. // @version 0.8.1.1
  4. // @description Monitors mturk.com for HITs
  5. // @author ThisPoorGuy
  6. // @icon http://nopurpose.org/stuff/avatars/Lj21396.gif
  7. // @include https://worker.mturk.com/?finder_beta
  8. // @include https://worker.mturk.com/?hit_forker
  9. // @grant GM_log
  10. // @grant GM_setClipboard
  11. // @grant GM_xmlhttpRequest
  12. // @connect turkerview.com
  13. // @require https://code.jquery.com/jquery-3.1.0.min.js
  14.  
  15. // @namespace https://gf.qytechs.cn/users/163167
  16. // ==/UserScript==
  17.  
  18. // Acknowledgements
  19. // The core of this script was forked/stolen/adapted from Kadauchi's Hit Finder Beta script. Coding assistance in spots
  20. // provided by Salem Beats and ChrisTurk. TurkerView was created by ChrisTurk. This script hooks into JR Panda Crazy
  21.  
  22. // Changelog
  23. // 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.
  24. // 0.8.1 - Fixed a couple of export formatting bugs.
  25. // 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.
  26. // Working on adding requesting for auto-grant quals, but that's...trickier.
  27. // 0.7.6 - Fixed issue with the search qualified check box not working.
  28. // 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.
  29. // 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
  30. // 0.7.3 - Returned a semi-colon to it's rightful position, even though it wasn't missed
  31. // 0.7.2 - Made it so that the Panda button sets pandas without once=true set. Whoops.
  32. // 0.7.0 - Big under the hood changes with how TV and TO review scores are gathered.
  33. // 0.6.5 - Further modifications to prevent availibility of external sites causing HF to stop randomly.
  34. // 0.6.4 - Send RequesterID over to PandaCrazy along with the other info.
  35. // 0.6.3 - Bringing PC functionality in house
  36. // 0.6.1 - Fixed panda button shading
  37. // 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.
  38. // 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...
  39. // 0.5.2 - Code cleanup.
  40. // 0.5.1 - Fixed the panda buttons on the Found hits table.
  41. // 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?
  42. // - Fixed a stupid typo in a variable name.
  43. // 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.
  44. // 0.4.2 - Link to TV Requester profile in export.
  45. // 0.4.1 - Show/Hide HITs and Logged Hits settings are now saved across sessions
  46. // 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
  47. // 0.3.5 - Added a button to hide the new HITS table. Moved the button to hide the logged hits for consistancy.
  48. // 0.3.2 - Modified icon for desktop notifications. Added Requester TV score to hit export
  49. // 0.3.1 - Fix for amazon screwing with things. Thanks ChrisTurk!
  50. // 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
  51. // 0.2.9 - Now acceptable to people with red/green color blindness!
  52. // 0.2.6 - Fixed a minor error which caused colors to not work properly.
  53. // 0.2.5 - Changed Coloration to respect TV reviews FIRST and then fall back on TO Values. Also changed colors.
  54. // 0.2.0 - Added TurkerView Hourly ratings to HIT results, fixed export links.
  55. // 0.1.5 - Some minor UI tweaks
  56. // 0.1.4 - Added some indication that you have already clicked a button to send HIT to PC. Only works in log currently.
  57. // 0.1.3 - Fixed issue with the Panda buttons in the HIT log not having the right GID
  58. // 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.
  59. // 0.1.1 - Cleaned up the header, removed unused audio files
  60. // 0.1.0 - Made modifications to launch links with worker website. Added buttons to send information to PandaCrazy directly instead of copying link
  61. // TODO:
  62. // Remove www code
  63. // Clean up interface
  64. // Delete the above todos because they're already done.
  65.  
  66. var worker = true;
  67.  
  68. var _config = JSON.parse(localStorage.getItem('_finder')) || {};
  69. var blocklist = JSON.parse(localStorage.getItem('_finder_bl')) || {};
  70. var includelist = JSON.parse(localStorage.getItem('_finder_il')) || {};
  71.  
  72. // Compatability check
  73. if (_config.version !== '1.1') { _config = {}; }
  74.  
  75. var config = {
  76. version : _config.version || '1.1',
  77. delay : _config.delay || '3',
  78. type : _config.type || 'LastUpdatedTime%3A1&pageSize=',
  79. size : _config.size || '25',
  80. rew : _config.rew || '0.00',
  81. avail : _config.avail || '0',
  82. mto : _config.mto || '0.00',
  83. alert : _config.alert || '0',
  84. qual : _config.hasOwnProperty('qual') ? _config.qual : true,
  85. new : _config.hasOwnProperty('new') ? _config.new : true,
  86. newaudio : _config.newaudio || 'beep',
  87. pb : _config.hasOwnProperty('pb') ? _config.pb : false,
  88. to : _config.hasOwnProperty('to') ? _config.to : true,
  89. tv : _config.hasOwnProperty('tv') ? _config.tv : true,
  90. nl : _config.hasOwnProperty('nl') ? _config.nl : false,
  91. bl : _config.hasOwnProperty('bl') ? _config.bl : false,
  92. m : _config.hasOwnProperty('m') ? _config.m : false,
  93. push : _config.push || 'access_token_here',
  94. theme : _config.theme || 'default',
  95. custom : _config.custom || {main: 'FFFFFF', primary: 'CCCCCC', secondary: '111111', text: '000000', link: '0000EE', visited: '551A8B', prop : false},
  96. to_theme : _config.to_theme || '1',
  97. h_hidden : _config.h_hidden || '0',
  98. l_hidden : _config.l_hidden || '0'
  99. };
  100.  
  101. var themes = {
  102. 'default' : {main: 'FFFFFF', primary: 'CCCCCC', secondary: '111111', menu: '373b44', menutext: 'FFFFFF', text: '000000', link: '0000EE', visited: '551A8B', prop : true},
  103. 'light' : {main: 'FFFFFF', primary: 'CCCCCC', secondary: '111111', menu: '373b44', menutext: 'FFFFFF', text: '000000', link: '0000EE', visited: '551A8B', prop : true},
  104. 'dark' : {main: '404040', primary: '666666', secondary: 'FFFFFF', menu: '202020', menutext: 'FFFFFF', text: 'FFFFFF', link: 'FFFFFF', visited: 'B3B3B3', prop : true},
  105. 'darker' : {main: '000000', primary: '262626', secondary: 'FFFFFF', menu: '373b44', menutext: 'FFFFFF', text: 'FFFFFF', link: 'FFFFFF', visited: 'B3B3B3', prop : true},
  106. 'custom' : config.custom
  107. };
  108.  
  109. var turkerview = { };
  110. var turkerview_update = 0;
  111. var requesters = [ ];
  112. var tvTimeoutCache = [ ];
  113.  
  114. var searches = 0,
  115. logged = 0,
  116. hitlog = {},
  117. noti_delay = [],
  118. push_delay = [];
  119.  
  120. // General Configuration variables
  121. var url, upd, num, rew, minrew, searchqual, pandaurl;
  122.  
  123. url = 'https://worker.mturk.com/?';
  124. pandaurl = 'https://worker.mturk.com';
  125. upd = '&sort=updated_desc&page_size=';
  126. num = '&sort=num_hits_desc&page_size=';
  127. rew = '&sort=reward_desc&page_size=';
  128. minrew = '&filters%5Bmin_reward%5D=';
  129. searchqual = '&filters%5Bqualified=';
  130.  
  131. var PandaCrazy = (function createPandaCrazy() {
  132. let _self = this;
  133.  
  134. let _lastSentPingTime;
  135. let _lastReceivedPongTime;
  136.  
  137. let _onlineSinceLastPing;
  138.  
  139. let _pcListener;
  140.  
  141. const MAX_WAIT_FOR_PANDA_CRAZY_RESPONSE_MS = 1000;
  142.  
  143. function ping() {
  144. _lastSentPingTime = Date.now();
  145. localStorage.setItem("JR_message_ping_pandacrazy", `{"theTarget": "${Math.random()}"}`);
  146. }
  147.  
  148. function hasIndicatedOnlineSinceLastPing() {
  149. if(_lastSentPingTime !== undefined && _lastReceivedPongTime !== undefined) {
  150. return _lastReceivedPongTime >= _lastSentPingTime;
  151. }
  152. else {
  153. return undefined;
  154. }
  155. }
  156.  
  157. function online() {
  158.  
  159. function respondToStorage(resolve, reject, e) {
  160. if(e.key.includes("JR_message_pong") && Boolean(e.newValue)) {
  161.  
  162. _lastReceivedPongTime = Date.now();
  163.  
  164. let pongData = JSON.parse(e.newValue);
  165.  
  166. let lag = Number(pongData.time) - Number(_lastReceivedPongTime);
  167.  
  168. if(hasIndicatedOnlineSinceLastPing()) {
  169. resolve("online");
  170. }
  171. }
  172. }
  173.  
  174. let isOnlinePromise = new Promise((resolve, reject) => {
  175.  
  176. setTimeout(() => {reject("timeout");}, MAX_WAIT_FOR_PANDA_CRAZY_RESPONSE_MS);
  177.  
  178. if(_pcListener) {window.removeEventListener("storage", _pcListener);}
  179.  
  180. _pcListener = respondToStorage.bind(window, resolve, reject);
  181.  
  182. window.addEventListener("storage", _pcListener);
  183.  
  184. /*
  185. window.addEventListener("storage", e => {
  186.  
  187. // console.log("Storage Event", e);
  188.  
  189. if(e.key.includes("JR_message_pong") && Boolean(e.newValue)) {
  190.  
  191. _lastReceivedPongTime = Date.now();
  192.  
  193. let pongData = JSON.parse(e.newValue);
  194.  
  195. let lag = Number(pongData.time) - Number(_lastReceivedPongTime);
  196.  
  197. if(hasIndicatedOnlineSinceLastPing()) {
  198. resolve("online");
  199. }
  200. }
  201. });
  202. */
  203. });
  204.  
  205. ping();
  206.  
  207. return isOnlinePromise;
  208. }
  209.  
  210. function addJob(gid, once, metadata) {
  211. let commandString = once ? "addOnceJob" : "addJob";
  212.  
  213. localStorage.setItem("JR_message_pandacrazy", JSON.stringify({
  214. time: Date.now(),
  215. command: commandString,
  216. data: {
  217. groupId: gid,
  218. title: (metadata ? metadata.hitTitle || metadata.title : undefined),
  219. requesterName: (metadata ? metadata.requesterName : undefined),
  220. requesterId: (metadata ? metadata.requesterID || metadata.requesterId || metadata.rid : undefined),
  221. pay: (metadata ? metadata.hitValue || metadata.pay : undefined),
  222. duration: (metadata ? metadata.duration : undefined),
  223. hitsAvailable: (metadata ? metadata.hitsAvailable : undefined)
  224. }
  225. }));
  226. }
  227.  
  228. function startJob(gid) {
  229. localStorage.setItem("JR_message_pandacrazy", JSON.stringify({
  230. time: Date.now(),
  231. command: "startcollect",
  232. data: {
  233. groupId: gid
  234. }
  235. }));
  236. }
  237.  
  238. return {
  239. addJob,
  240. startJob,
  241. ping,
  242. online
  243. };
  244. })();
  245.  
  246. $('head').html(
  247. '<title>HIT Forker</title>' +
  248. '<link rel="icon" type="image/jpg" href="http://nopurpose.org/stuff/avatars/Lj21396.gif">' +
  249. '<base target="_blank">' +
  250.  
  251. '<audio id="audio_1"><source src="http://www.soundjay.com/button/sounds/button-1.mp3" type="audio/mpeg"></audio>' +
  252. '<audio id="audio_2"><source src="http://www.soundjay.com/button/sounds/button-3.mp3" type="audio/mpeg"></audio>' +
  253. '<audio id="audio_3"><source src="http://www.soundjay.com/button/sounds/button-4.mp3" type="audio/mpeg"></audio>' +
  254. '<audio id="audio_4"><source src="http://www.soundjay.com/button/sounds/button-5.mp3" type="audio/mpeg"></audio>' +
  255. '<audio id="audio_beep"><source src="http://www.soundjay.com/button/sounds/beep-21.mp3" type="audio/mpeg"></audio>' +
  256. '<audio id="audio_beepbeep"><source src="http://www.soundjay.com/button/sounds/beep-24.mp3" type="audio/mpeg"></audio>' +
  257. '<audio id="audio_click"><source src="http://www.soundjay.com/button/sounds/button-20.mp3" type="audio/mpeg"></audio>' +
  258.  
  259. '<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css" rel="stylesheet">' +
  260. '<style id="css" type="text/css">'
  261. );
  262.  
  263. $('body').html(
  264. // Main
  265. '<div style="margin-bottom: 5px; text-align:right;" id="menubar">' +
  266. '<div style="position: absolute; top: 32px width: 100px; font-size: 14pt; font-weight: bold;" id="menu_title">HIT Forker</div>'+
  267. '<div style="line-height: 30px; margin-right:5px;">'+
  268. '<button id="scan_button" style="margin-right: 5px;">Start</button>' +
  269. '<button id="bloc_button" style="margin-right: 5px;">Block List</button>' +
  270. '<button id="incl_button" style="margin-right: 5px;">Include List</button>' +
  271. '<button id="sett_button" style="margin-right: 5px;">Advanced Settings</button>' +
  272. '<button id="conf_button" style="margin-right: 5px;">Show Config</button>' +
  273.  
  274. '</div></div>' +
  275.  
  276. // Config
  277. '<div id="config" style="position: absolute; top: 37px; right: 5px; margin-bottom: 5px;" class="hidden">' +
  278.  
  279. '<div style="margin-bottom: 5px;">' +
  280. '<label style="margin-right: 5px; display: inline-block; border-bottom: 1px solid;" title="Delay in seconds between searches.">Search Delay: ' +
  281. '<input id="delay" style="width: 50px;" type="number" step="1" min="1" value="' + config.delay + '">' +
  282. '</label>' +
  283.  
  284. '<label style="margin-right: 5px; display: inline-block; border-bottom: 1px solid;" title="Filter HITs by minimum reward.">Min Reward: ' +
  285. '<input id="min_rew" style="width: 50px;" type="number" step="0.01" min="0" value="' + config.rew + '">' +
  286. '</label>' +
  287.  
  288. '<label style="margin-right: 5px; display: inline-block; border-bottom: 1px solid;" title="Filter HITs by minimum available.">Min Avail: ' +
  289. '<input id="min_avail" style="width: 50px;" type="number" step="1" min="0" value="' + config.avail + '">' +
  290. '</label>' +
  291.  
  292. '<label style="margin-right: 5px; display: inline-block; border-bottom: 1px solid;" title="Filter HITs by minimum TO pay.">Min TO: ' +
  293. '<input id="min_to" style="width: 50px;" type="number" step="0.1" min="0" max="5" value="' + config.mto + '">' +
  294. '</label>' +
  295.  
  296. '<label style="margin-right: 5px; display: inline-block; border-bottom: 1px solid;" title="Search for this many HITs.">Size: ' +
  297. '<input id="size" style="width: 50px;" type="number" step="1" min="1" max="100" value="' + config.size + '">' +
  298. '</label>' +
  299.  
  300. '<label style="margin-right: 5px; display: inline-block; border-bottom: 1px solid;" title="Sort HITs by (Latest / Most Available / Highest Reward)">Sort by: ' +
  301. '<select id="type" value="' + config.type + '">' +
  302. '<option value="' + upd + '">Latest</option>' +
  303. '<option value="' + num + '">Most Available</option>' +
  304. '<option value="' + rew + '">Reward (Most)</option>' +
  305. '</select>' +
  306. '</label>' +
  307.  
  308. '<label style="margin-right: 0px; display: inline-block; border-bottom: 1px solid;" title="Only show HITs that you are for.">Qualified' +
  309. '<input id="qual" type="checkbox" ' + (config.qual ? 'checked' : '') + '>' +
  310. '</label>' +
  311. '</div>' +
  312.  
  313. '<div style="margin-bottom: 5px;">' +
  314. '<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: ' +
  315. '<input id="alert_delay" style="width: 50px;" type="number" step="1" min="0" value="' + config.alert + '">' +
  316. '</label>' +
  317.  
  318. '<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 ' +
  319. '<input id="new_sound" type="checkbox" ' + (config.new ? 'checked' : '') + '>' +
  320. '<select id="new_audio" value="' + config.newaudio + '">' +
  321. //'<option value="default">Default</option>' +
  322. '<option value="beep">Beep</option>' +
  323. '<option value="beepbeep">Beep Beep</option>' +
  324. //'<option value="ding">Ding</option>' +
  325. //'<option value="squee">Squee</option>' +
  326. '<option value="click">Click</option>' +
  327. '</select>' +
  328. '</label>' +
  329.  
  330. '<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 ' +
  331. '<input id="pb" type="checkbox" ' + (config.pb ? 'checked' : '') + '>' +
  332. '</label>' +
  333.  
  334. '<label style="margin-right: 5px; display: inline-block; border-bottom: 1px solid;" title="Use turkopticon.">Enable TO ' +
  335. '<input id="to" type="checkbox" ' + (config.to ? 'checked' : '') + '>' +
  336. '</label>' +
  337.  
  338. '<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 ' +
  339. '<input id="nl_hide" type="checkbox" ' + (config.nl ? 'checked' : '') + '>' +
  340. '</label>' +
  341.  
  342. '<label style="margin-right: 5px; display: inline-block; border-bottom: 1px solid;" title="Hide HITs that match your block list.">Hide Block List ' +
  343. '<input id="bl_hide" type="checkbox" ' + (config.bl ? 'checked' : '') + '>' +
  344. '</label>' +
  345.  
  346. '</div>' +
  347.  
  348. '</div>' +
  349.  
  350. // HITs
  351. '<div id="latest_hits">' +
  352. '<div style="border-bottom: 3px solid; margin-bottom: 5px;">' +
  353. '<span style="font-size: 20px; font-weight: bold;">HITs</span>' +
  354. '<span id="hits_data" style="font-size: 11px;"></span>' +
  355. '<span id="hits_controls" style="float: right"><button id="hits_button" style="margin-right: 5px;">Hide New HITs</button></span>' +
  356. '</div>' +
  357. '<div id="hits_hidden" style="text-align: center; display: none;">--- HITS HIDDEN ---</div>' +
  358. '<div id="hits_table">' +
  359. '<div>' +
  360. '<div style="overflow: hidden; white-space: nowrap;">' +
  361. '<div style="float: left; width: calc(100% - 330px);">' +
  362. '<span style="width: 34%; float: left; display:inline-block; overflow: hidden;">Requester</span>' +
  363. '<span style="width: 64%; float: right; display:inline-block; overflow: hidden;">Project</span>' +
  364. '</div>' +
  365.  
  366. '<div style="float: right;">' +
  367. '<span style="width: 60px; display:inline-block; text-align: center;">Tasks</span>' +
  368. '<span style="width: 60px; display:inline-block; text-align: center;">Accept</span>' +
  369. '<span style="width: 60px; display:inline-block; text-align: center;">TV</span>' +
  370. '<span style="width: 60px; display:inline-block; text-align: center;">TO</span>' +
  371. '<span style="width: 60px; display:inline-block; text-align: center;">PANDA</span>' +
  372. '</div>' +
  373. '</div>' +
  374. '</div>' +
  375. '<div id="new_hits_"></div>' +
  376. '</div>' +
  377. '</div>' +
  378.  
  379. '<br>' +
  380.  
  381. //Logged HITs
  382. '<div id="logged_hits">' +
  383. '<div style="border-bottom: 3px solid; margin-bottom: 5px;">' +
  384. '<span style="font-size: 20px; font-weight: bold;">Logged HITs</span>' +
  385. '<span id="logged_hits_data" style="font-size: 11px;"></span>' +
  386. '<span id="log_controls" style="float: right"><button id="logg_button" style="margin-right: 0px;">Hide Logged HITs</button></span>' +
  387. '</div>' +
  388. '<div id="log_hidden" style="text-align: center; display: none;">--- LOGGED HITS HIDDEN ---</div>' +
  389. '<div id="log_table">' +
  390. '<div>' +
  391. '<div style="overflow: hidden; white-space: nowrap;">' +
  392.  
  393. '<div style="float: left;">' +
  394. '<span style="width: 80px; display:inline-block;">Time</span>' +
  395. '</div>' +
  396.  
  397. '<div style="float: left; width: calc(100% - 3500px);">' +
  398. '<span style="width: 25%; float: left; display:inline-block; overflow: hidden;">Requester</span>' +
  399. '<span style="width: 75%; float: right; display:inline-block; overflow: hidden;">Project</span>' +
  400.  
  401. '</div>' +
  402.  
  403. '<div style="float: right;">' +
  404. '<span style="width: 60px; display:inline-block; text-align: center;">Avail</span>' +
  405. '<span style="width: 60px; display:inline-block; text-align: center;">Accept</span>' +
  406. '<span style="width: 60px; display:inline-block; text-align: center;">TV</span>' +
  407. '<span style="width: 60px; display:inline-block; text-align: center;">TO</span>' +
  408. '<span style="width: 60px; display:inline-block; text-align: center;">PANDA</span>' +
  409. '</div>' +
  410. '</div>' +
  411. '</div>' +
  412. '<div id="log_hits_"></div>' +
  413. '</div>' +
  414. '</div>' +
  415.  
  416. // Block List
  417. '<div id="bl_div" style="z-index: 99; position: fixed; width: 80%; height: 80%; left: 10%; top: 300px; margin-top: -250px; display: none;">' +
  418. '<div style="position: relative; width: 80%; left: 10%; border-bottom: 3px solid; padding: 2px; text-align: center;">Block List</div>' +
  419. '<div id="bl_items"></div>' +
  420. '<div style="text-align: center;">' +
  421. '<button id="bl_add" style="margin-right: 5px;">Add</button>' +
  422. '<button id="bl_close" style="margin-right: 5px;">Close</button>' +
  423. '<button id="bl_import" style="margin-right: 5px;">Import</button>' +
  424. '<button id="bl_export" style="margin-right: 0px;">Export</button>' +
  425. '</div>' +
  426. '</div>' +
  427.  
  428. // Add Block List Popup
  429. '<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;">' +
  430. '<div style="position: relative; width: 80%; left: 10%; border-bottom: 3px solid; padding: 2px; text-align: center;">Add To Block List</div>' +
  431.  
  432. '<div>' +
  433. '<p><label>Term: </label><input id="bl_term" value="" maxlength="300"></p>' +
  434. '<p><label>Name: </label><input id="bl_name" value="" maxlength="300"></p>' +
  435. '<input id="bl_gid" value="0" type="hidden">' +
  436. '</div>' +
  437.  
  438. '<div>' +
  439. '<button id="bl_add_save" style="margin-right: 5px;">Save</button>' +
  440. '<button id="bl_add_cancel" style="margin-right: 0px;">Cancel</button>' +
  441. '</div>' +
  442. '</div>' +
  443.  
  444. // Edit Block List Popup
  445. '<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;">' +
  446. '<div style="position: relative; width: 80%; left: 10%; border-bottom: 3px solid; padding: 2px; text-align: center;">Edit Block List Item</div>' +
  447.  
  448. '<div>' +
  449. '<p><label>Term: </label><input id="edit_bl_term" value=""disabled></p>' +
  450. '<p><label>Name: </label><input id="edit_bl_name" value=""></p>' +
  451. '</div>' +
  452.  
  453. '<div>' +
  454. '<button id="edit_bl_save" style="margin-right: 5px;">Save</button>' +
  455. '<button id="edit_bl_delete" style="margin-right: 5px;">Delete</button>' +
  456. '<button id="edit_bl_cancel" style="margin-right: 0px;">Cancel</button>' +
  457. '</div>' +
  458. '</div>' +
  459.  
  460. // Include List
  461. '<div id="il_div" style="z-index: 99; position: fixed; width: 80%; height: 80%; left: 10%; top: 300px; margin-top: -250px; display: none;">' +
  462. '<div style="position: relative; width: 80%; left: 10%; border-bottom: 3px solid; padding: 2px; text-align: center;">Include List</div>' +
  463. '<div id="il_items"></div>' +
  464. '<div style="text-align: center;">' +
  465. '<button id="il_add" style="margin-right: 5px;">Add</button>' +
  466. '<button id="il_close" style="margin-right: 5px;">Close</button>' +
  467. '<button id="il_import" style="margin-right: 5px;">Import</button>' +
  468. '<button id="il_export" style="margin-right: 0px;">Export</button>' +
  469. '</div>' +
  470. '</div>' +
  471.  
  472. // Add Include List Popup
  473. '<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;">' +
  474. '<div style="position: relative; width: 80%; left: 10%; border-bottom: 3px solid; padding: 2px; text-align: center;">Add To Include List</div>' +
  475.  
  476. '<div>' +
  477. '<p><label>Term: </label><input id="il_term" value=""></p>' +
  478. '<p><label>Name: </label><input id="il_name" value=""></p>' +
  479. '</div>' +
  480.  
  481. '<div style="position: relative; width: 80%; left: 10%; border-bottom: 3px solid; padding: 2px; text-align: center;">Alerts</div>' +
  482.  
  483. '<p>' +
  484. '<label style="margin-right: 5px; display: inline-block; border-bottom: 1px solid;">Sound: ' +
  485. '<select id="il_sound">' +
  486. '<option value="1">Sound 1</option>' +
  487. '<option value="2">Sound 2</option>' +
  488. '<option value="3">Sound 3</option>' +
  489. '<option value="4">Sound 4</option>' +
  490. '</select>' +
  491. '</label>' +
  492.  
  493. '<label style="margin-right: 5px; display: inline-block; border-bottom: 1px solid;">Desktop Notifications' +
  494. '<input id="il_noti_cb" type="checkbox">' +
  495. '</label>' +
  496.  
  497. '<label style="margin-right: 5px; display: inline-block; border-bottom: 1px solid;">Play Sound' +
  498. '<input id="il_sound_cb" type="checkbox">' +
  499. '</label>' +
  500.  
  501. '<label style="margin-right: 5px; display: inline-block; border-bottom: 1px solid;">Send Pushbullet' +
  502. '<input id="il_push_cb" type="checkbox">' +
  503. '</label>' +
  504. '</p>' +
  505.  
  506. '<div>' +
  507. '<button id="il_add_save" style="margin-right: 5px;">Save</button>' +
  508. '<button id="il_add_cancel" style="margin-right: 0px;">Cancel</button>' +
  509. '</div>' +
  510. '</div>' +
  511.  
  512. // Edit Include List Popup
  513. '<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;">' +
  514. '<div style="position: relative; width: 80%; left: 10%; border-bottom: 3px solid; padding: 2px; text-align: center;">Edit Include List Item</div>' +
  515.  
  516. '<div>' +
  517. '<p><label>Term: </label><input id="edit_il_term" value="" disabled></p>' +
  518. '<p><label>Name: </label><input id="edit_il_name" value=""></p>' +
  519. '</div>' +
  520.  
  521. '<div style="position: relative; width: 80%; left: 10%; border-bottom: 3px solid; padding: 2px; text-align: center;"">Alerts</div>' +
  522.  
  523. '<p>' +
  524. '<label style="margin-right: 5px; display: inline-block; border-bottom: 1px solid;">Sound: ' +
  525. '<select id="edit_il_sound">' +
  526. '<option value="1">Sound 1</option>' +
  527. '<option value="2">Sound 2</option>' +
  528. '<option value="3">Sound 3</option>' +
  529. '<option value="4">Sound 4</option>' +
  530. '</select>' +
  531. '</label>' +
  532.  
  533. '<label style="margin-right: 5px; display: inline-block; border-bottom: 1px solid;">Desktop Notifications' +
  534. '<input id="edit_il_noti_cb" type="checkbox">' +
  535. '</label>' +
  536.  
  537. '<label style="margin-right: 5px; display: inline-block; border-bottom: 1px solid;">Play Sound' +
  538. '<input id="edit_il_sound_cb" type="checkbox">' +
  539. '</label>' +
  540.  
  541. '<label style="margin-right: 0px; display: inline-block; border-bottom: 1px solid;">Send Pushbullet' +
  542. '<input id="edit_il_push_cb" type="checkbox">' +
  543. '</label>' +
  544. '</p>' +
  545.  
  546. '<div>' +
  547. '<button id="edit_il_save" style="margin-right: 5px;">Save</button>' +
  548. '<button id="edit_il_delete" style="margin-right: 5px;">Delete</button>' +
  549. '<button id="edit_il_cancel" style="margin-right: 0px;">Cancel</button>' +
  550. '</div>' +
  551. '</div>' +
  552.  
  553. // Advanced Settings
  554. '<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;">' +
  555. '<div style="position: relative; width: 80%; left: 10%; border-bottom: 3px solid; padding: 2px; text-align: center;">Advanced Settings</div>' +
  556.  
  557. '<div>' +
  558. '<p><label>Pushbullet Token: </label><input id="push" value="' + config.push + '"></p>' +
  559. '</div>' +
  560.  
  561. '<div style="position: relative; width: 80%; left: 10%; border-bottom: 3px solid; padding: 2px; text-align: center;">Theme</div>' +
  562.  
  563. '<p>' +
  564. '<label style="margin-right: 5px; display: inline-block; border-bottom: 1px solid;">Theme: ' +
  565. '<select id="adv_theme" value="' + config.theme + '">' +
  566. '<option value="default">Default (Light)</option>' +
  567. '<option value="light">Pastel</option>' +
  568. '<option value="dark">Dark</option>' +
  569. '<option value="darker">Darker</option>' +
  570. '<option value="custom">Custom</option>' +
  571. '</select>' +
  572. '</label>' +
  573.  
  574. '<label style="margin-right: 0px; display: inline-block; border-bottom: 1px solid;">TO Theme: ' +
  575. '<select id="to_theme" value="' + config.to_theme + '">' +
  576. '<option value="1">Default</option>' +
  577. '<option value="2">Column Only</option>' +
  578. '<option value="3">Text Only</option>' +
  579. '</select>' +
  580. '</label>' +
  581. '</p>' +
  582.  
  583. '<p>' +
  584. '<label style="width: 150px; margin-right: 5px; display: inline-block; border-bottom: 1px solid; text-align: left;">Main: #' +
  585. '<input id="theme_main" style="width: 55px; float: right;" maxlength="6">' +
  586. '</label>' +
  587.  
  588. '<label style="width: 150px; margin-right: 5px; display: inline-block; border-bottom: 1px solid; text-align: left;">Primary: #' +
  589. '<input id="theme_primary" style="width: 55px; float: right;" maxlength="6">' +
  590. '</label>' +
  591.  
  592. '<label style="width: 150px; margin-right: 0px; display: inline-block; border-bottom: 1px solid; text-align: left;">Secondary: #' +
  593. '<input id="theme_secondary" style="width: 55px; float: right;" maxlength="6">' +
  594. '</label>' +
  595. '</p>' +
  596.  
  597. '<p>' +
  598. '<label style="width: 150px; margin-right: 5px; display: inline-block; border-bottom: 1px solid; text-align: left;">Text: #' +
  599. '<input id="theme_text" style="width: 55px; float: right;" maxlength="6">' +
  600. '</label>' +
  601.  
  602. '<label style="width: 150px; margin-right: 5px; display: inline-block; border-bottom: 1px solid; text-align: left;">Link: #' +
  603. '<input id="theme_link" style="width: 55px; float: right;" maxlength="6">' +
  604. '</label>' +
  605.  
  606. '<label style="width: 150px; margin-right: 0px; display: inline-block; border-bottom: 1px solid; text-align: left;">Visited: #' +
  607. '<input id="theme_visited" style="width: 55px; float: right;" maxlength="6">' +
  608. '</label>' +
  609. '</p>' +
  610.  
  611. '<div>' +
  612. '<button id="sett_save" style="margin-right: 5px;">Save</button>' +
  613. '<button id="sett_close" style="margin-right: 0px;">Close</button>' +
  614. '</div>' +
  615. '</div>'
  616. );
  617.  
  618. // Click functions
  619. $('#scan_button').click(function () {
  620. if ($(this).text() === 'Start') {
  621. $(this).text('Stop');
  622. _scan();
  623. }
  624. else {
  625. $(this).text('Start');
  626. }
  627. });
  628.  
  629. $('#sett_button').click(function () {
  630. $('#sett').toggle();
  631. });
  632.  
  633. $('#conf_button').click(function () {
  634. if ($(this).text() === 'Hide Config') {
  635. $(this).text('Show Config');
  636. }
  637. else {
  638. $(this).text('Hide Config');
  639. }
  640. $('#config').toggleClass('hidden');
  641. });
  642.  
  643. $('#logg_button').click(function () {
  644. _hide_log_list( $(this).text() === 'Hide Logged HITs' ? true : false );
  645. });
  646.  
  647. $('#hits_button').click(function () {
  648. _hide_hit_list( $(this).text() === 'Hide New HITs' ? true : false );
  649. });
  650.  
  651. $('#bloc_button').click(function () {
  652. $('#bl_div').toggle();
  653. });
  654.  
  655. $('#bl_add').click(function () {
  656. $('#bl').show();
  657. });
  658.  
  659. $('#bl_close').click(function () {
  660. $('#bl_div').hide();
  661. });
  662.  
  663. $('#bl_import').click(function () {
  664. _import_block();
  665. });
  666.  
  667. $('#bl_export').click(function () {
  668. _export_block();
  669. });
  670.  
  671. $('#bl_add_save').click(function () {
  672. var obj = {
  673. term : $('#bl_term').val(),
  674. name : $('#bl_name').val() === '' ? $('#bl_term').val() : $('#bl_name').val(),
  675. gid : $('#bl_gid').val() === '' ? 'X' : $('#bl_gid').val()
  676. };
  677.  
  678. _add_block(obj);
  679.  
  680. if ( obj.gid != 'X' ) {
  681. $('.loggid_' + obj.gid ).remove();
  682. }
  683. else {
  684. $('.logreqid_' + obj.term ).remove();
  685. }
  686.  
  687. $('#bl_term, #bl_name').val('');
  688. $('#bl').hide();
  689. });
  690.  
  691. $('#bl_add_cancel').click(function () {
  692. $('#bl_term, #bl_name').val('');
  693. $('#bl').hide();
  694. });
  695.  
  696. $('#edit_bl_save').click(function () {
  697. _update_block($(this).val());
  698. $('#edit_bl_term, #edit_bl_name').val('');
  699. $('#edit_bl').hide();
  700. });
  701.  
  702. $('#edit_bl_delete').click(function () {
  703. _delete_block($(this).val());
  704. $('#edit_bl_term, #edit_bl_name').val('');
  705. $('#edit_bl').hide();
  706. });
  707.  
  708. $('#edit_bl_cancel').click(function () {
  709. $('#edit_bl_term, #edit_bl_name').val('');
  710. $('#edit_bl').hide();
  711. });
  712.  
  713. $('#incl_button').click(function () {
  714. $('#il_div').toggle();
  715. });
  716.  
  717. $('#il_add').click(function () {
  718. $('#il').show();
  719. });
  720.  
  721. $('#il_close').click(function () {
  722. $('#il_div').hide();
  723. });
  724.  
  725. $('#il_import').click(function () {
  726. _import_include();
  727. });
  728.  
  729. $('#il_export').click(function () {
  730. _export_include();
  731. });
  732.  
  733. $('#il_add_save').click(function () {
  734. var obj = {
  735. term : $('#il_term').val().trim(),
  736. name : $('#il_name').val().trim() === '' ? $('#il_term').val().trim() : $('#il_name').val().trim(),
  737. sound : $('#il_sound').val(),
  738. noti_cb : $('#il_noti_cb').prop('checked'),
  739. sound_cb : $('#il_sound_cb').prop('checked'),
  740. push_cb : $('#il_push_cb').prop('checked')
  741. };
  742.  
  743. _add_include(obj);
  744.  
  745. $('#il_term, #il_name').val('');
  746. $('#il').hide();
  747. });
  748.  
  749. $('#il_add_cancel').click(function () {
  750. $('#il_term, #il_name').val('');
  751. $('#il').hide();
  752. });
  753.  
  754. $('#edit_il_save').click(function () {
  755. _update_include($(this).val());
  756. $('#edit_il_term, #edit_il_name, #edit_il_sound').val('');
  757. $('#edit_il_noti_cb, #edit_il_sound_cb, #edit_il_push_cb').prop('checked', false);
  758. $('#edit_il').hide();
  759. });
  760.  
  761. $('#edit_il_delete').click(function () {
  762. _delete_include($(this).val());
  763. $('#edit_il_term, #edit_il_name, #edit_il_sound').val('');
  764. $('#edit_il_noti_cb, #edit_il_sound_cb, #edit_il_push_cb').prop('checked', false);
  765. $('#edit_il').hide();
  766. });
  767.  
  768. $('#edit_il_cancel').click(function () {
  769. $('#edit_il_term, #edit_il_name, #edit_il_sound').val('');
  770. $('#edit_il_noti_cb, #edit_il_sound_cb, #edit_il_push_cb').prop('checked', false);
  771. $('#edit_il').hide();
  772. });
  773.  
  774. $('.on, .off').click(function () {
  775. $(this).toggleClass('on off');
  776. _save();
  777. });
  778.  
  779. $('#sett_save').click(function () {
  780. _save('custom');
  781. _theme();
  782. });
  783.  
  784. $('#sett_close').click(function () {
  785. $('#sett').hide();
  786. });
  787.  
  788. $('#time').click(function () {
  789. $('.new').removeClass('new');
  790. });
  791.  
  792. // Delegated click functions
  793. $('body').on('click', '.blockit', function () {
  794. _edit_block($(this).val());
  795. });
  796.  
  797. $('body').on('click', '.includeit', function () {
  798. _edit_include($(this).val());
  799. });
  800.  
  801. $('body').on('click', '.rt', function () {
  802. _block($(this).data('term'), $(this).data('name'), $(this).attr('id'));
  803. });
  804.  
  805. $('body').on('click', '.pc', function () {
  806. _panda($(this).data('term'), $(this).data('reqname'), $(this).data('reqid'), $(this).data('title'), $(this).data('value'), $(this).data('name'), $(this))
  807. });
  808.  
  809. $('body').on('click', '.vb', function () {
  810. _export_vb($(this).val());
  811. });
  812.  
  813. $('body').on('click', '.irc', function () {
  814. _export_irc($(this).val());
  815. });
  816.  
  817. $('body').on('click', '.details', function () {
  818. $(this).toggleClass('fa-plus-circle fa-minus-circle');
  819. $('.info[value="' + $(this).val() + '"]').toggle();
  820. });
  821.  
  822. // Delegated mouseover functions
  823. $('body').on('mouseover', '.new', function () {
  824. $(this).removeClass('new');
  825. });
  826.  
  827. // On change events
  828. $('#new_audio').change(function () {
  829. _save();
  830. _sound('new');
  831. });
  832.  
  833. $('#il_sound').change(function () {
  834. _sound('il');
  835. });
  836.  
  837. $('#edit_il_sound').change(function () {
  838. _sound('il_edit');
  839. });
  840.  
  841. $('#type, #size, #adv_theme, #to_theme, #c_theme, :checkbox').change(function () {
  842. _save();
  843. });
  844.  
  845. $('#adv_theme, #to_theme, #c_theme').change(function () {
  846. _theme();
  847. });
  848.  
  849. // On input events
  850. $('#delay, #min_rew, #min_avail, #min_to, #alert_delay').on('input', function () {
  851. _save();
  852. });
  853.  
  854. function extend(obj, src) {
  855. for (var key in src) {
  856. if (src.hasOwnProperty(key)) obj[key] = src[key];
  857. }
  858. return obj;
  859. }
  860.  
  861. function _scan () {
  862. var searchqualvar
  863. searchqualvar = (config.qual ? 'true' : 'false');
  864.  
  865.  
  866. if ($('#scan_button').text() === 'Stop') {
  867. var _url = url + $('#type').val() + $('#size').val() + minrew + $('#min_rew').val() + searchqual + searchqualvar;
  868. //console.log( _url );
  869. var _scanurl = _url + '&format=json';
  870.  
  871. var date = new Date(), h = date.getHours(), m = date.getMinutes(), s = date.getSeconds(), ampm = h >= 12 ? 'pm' : 'am';
  872. h = h % 12; h = h ? h : 12; m = m < 10 ? '0' + m : m; s = s < 10 ? '0' + s : s;
  873. var timeis = [h, m, s, ampm];
  874. console.log( _scanurl );
  875. $.get(_scanurl, function (data) {
  876. _scrape_new(data, timeis);
  877. }).fail(function () {
  878. setTimeout(function () { _scan(); }, 2500);
  879. });
  880. }
  881. }
  882.  
  883. function _scrape_new (data, timeis) {
  884. var keys = [], log_keys = [], to = [], logged_in = true;
  885. var new_requesters = [];
  886. var hits = data.results;
  887.  
  888. for (var i = 0; i < hits.length; i ++) {
  889. var hit = hits[i],
  890. req_name = hit.requester_name,
  891. req_id = hit.requester_id,
  892. req_link = hit.requester_url.replace(/\.json/, ''),
  893. //req_link = 'https://www.mturk.com/mturk/searchbar?selectedSearchType=hitgroups&requesterId=' + hit.requester_id,
  894. con_link = 'https://www.mturk.com/mturk/contact?requesterId=' + hit.requester_id,
  895. group_id = hit.hit_set_id,
  896. prev_link = hit.project_tasks_url.replace(/\.json/, ''),
  897. //prev_link = 'https://www.mturk.com/mturk/preview?groupId=' + hit.hit_set_id,
  898. pand_link = hit.accept_project_task_url.replace(/\.json/, ''),
  899. //pand_link = 'https://www.mturk.com/mturk/previewandaccept?groupId=' + hit.hit_set_id,
  900. title = hit.title,
  901. safetitle = title.replace(/"/g, "&quot;" ),
  902. desc = hit.description,
  903. time = _convert_seconds(hit.assignment_duration_in_seconds),
  904. reward = '$' + hit.monetary_reward.amount_in_dollars.toFixed(2),
  905. avail = hit.assignable_hits_count;
  906.  
  907. var key = req_id + title + reward + group_id;
  908. keys.push(key);
  909.  
  910. var qualif = 'None';
  911. var quals = hit.project_requirements;
  912.  
  913.  
  914. if (quals.length) {
  915.  
  916. qualif = '';
  917. for (var j = 0; j < quals.length; j ++) {
  918. var q_comp = quals[j].comparator + ' ';
  919. var q_name = quals[j].qualification_type.name + ' ';
  920.  
  921. var q_valu = quals[j].qualification_values;
  922. var q_values = '';
  923. for (var k = 0; k < quals.length; k ++) {
  924. if (quals[j].qualification_values[k]) {
  925. q_values += quals[j].qualification_values[k];
  926. q_values += k === quals.length ? ', ' : '';
  927. }
  928. }
  929. if ( typeof quals[j].qualification_request_url !== 'undefined' ) {
  930. q_values += '~!~' + quals[j].qualification_request_url;
  931. }
  932. qualif += (q_name + q_comp + q_values).trim() + '; ';
  933. }
  934. qualif = qualif.trim();
  935. }
  936.  
  937. if (!hitlog[key]) {
  938. hitlog[key] = {
  939. reqname : req_name,
  940. reqid : req_id,
  941. reqlink : req_link,
  942. conlink : con_link,
  943. groupid : group_id,
  944. prevlink : prev_link,
  945. pandlink : pand_link,
  946. title : title,
  947. safetitle: safetitle,
  948. desc : desc,
  949. time : time,
  950. reward : reward,
  951. avail : avail,
  952. quals : qualif,
  953. key : key,
  954. tolink : 'https://turkopticon.ucsd.edu/' + req_id,
  955. to : { comm : 'N/A', fair : 'N/A', fast : 'N/A', pay : 'N/A' },
  956. tvlink : 'https://turkerview.com/requesters/' + req_id,
  957. tv : 'N/A'
  958. };
  959.  
  960. if ( $.inArray( req_id, requesters ) == -1 ) {
  961. new_requesters.push( req_id );
  962. }
  963.  
  964. to.push([key, req_id]);
  965. log_keys.push(key);
  966. }
  967. else {
  968. hitlog[key].avail = avail;
  969. }
  970. }
  971.  
  972. var tvPromise = _getTVReviews( new_requesters );
  973. var toPromise = _to(keys, log_keys, logged_in, to, timeis);
  974.  
  975. $.when( tvPromise, toPromise).done( function( v1, v2 ) {
  976. _build(keys, log_keys, timeis);
  977. }
  978. );
  979. }
  980.  
  981. function _getTVReviews( reqlist ) {
  982. var def = $.Deferred();
  983. if ( reqlist.length > 0 && config.tv ){
  984. var tvurl = 'https://api.turkerview.com/api/v1/requesters/?ids=' + reqlist.join() + '&from=tpg';
  985. var newreviews;
  986. GM_xmlhttpRequest ({
  987. method: "GET",
  988. url: tvurl,
  989. timeout: 4000,
  990. onload: function(response) {
  991. newreviews = JSON.parse(response.responseText);
  992. $.merge( requesters, reqlist );
  993. turkerview = extend( turkerview, newreviews);
  994. def.resolve( response );
  995. },
  996. ontimeout: function (response) {
  997. def.resolve('Timeout');
  998. },
  999. onerror: function (response) {
  1000. def.resolve('Error');
  1001. }
  1002. });
  1003. }
  1004. else {
  1005. def.resolve( 'Empty');
  1006. }
  1007.  
  1008. return def.promise();
  1009. }
  1010.  
  1011. function _getTVHourly( reqid ) {
  1012. var tvHourly;
  1013. if( reqid in turkerview ) {
  1014. tvHourly = '$' + turkerview[reqid]['ratings']['hourly'];
  1015. }
  1016. else {
  1017. tvHourly = 'N/A';
  1018. }
  1019.  
  1020. return tvHourly;
  1021. }
  1022.  
  1023. function _to (keys, log_keys, logged_in, to, timeis) {
  1024. var def = $.Deferred();
  1025.  
  1026. var ids = [];
  1027.  
  1028. if (logged_in && to.length && config.to) {
  1029. for (var i = 0; i < to.length; i++) {
  1030. ids.push(to[i][1]);
  1031. }
  1032.  
  1033. $.ajax( {
  1034. url: 'https://turkopticon.ucsd.edu/api/multi-attrs.php?ids=' + ids,
  1035. success: function (data) {
  1036. var to_data = JSON.parse(data);
  1037.  
  1038. for (i = 0; i < to.length; i++) {
  1039. if (!to_data[to[i][1]].length && typeof to_data[to[i][1]].attrs != 'undefined') {
  1040. hitlog[to[i][0]].to = to_data[to[i][1]].attrs;
  1041. }
  1042. }
  1043. },
  1044. timeout: 5000
  1045. }).always(function () {
  1046. def.resolve( 'Done' );
  1047. });
  1048. }
  1049. else {
  1050. def.resolve( 'TO Off' );
  1051. }
  1052. return def.promise();
  1053.  
  1054. }
  1055.  
  1056. function _build (keys, log_keys, timeis) {
  1057. var hit_html = '', log_html = '';
  1058.  
  1059. for (var i = 0; i < keys.length; i++) {
  1060. var hit = hitlog[keys[i]], blocked = _check_block(hit), included = _check_include(hit), remove = false, classes, tvHourly, tvScore = false;
  1061.  
  1062. hit.tv = _getTVHourly( hit.reqid );
  1063. if ( hit.tv.substring(0,3) == 'N/A' || hit.tv.substring(0,3) == '<sp' ) {
  1064. tvScore = false;
  1065. }
  1066. else {
  1067. tvScore = true;
  1068. }
  1069. rowcolor = tvScore == true ? _color_tv(hit) : _color_to(hit);
  1070.  
  1071. classes = rowcolor;
  1072.  
  1073. if (Number(config.avail) > Number(hit.avail) || Number(config.mto) > Number(hit.to.pay)) {
  1074. classes += ' hidden';
  1075. remove = true;
  1076. }
  1077.  
  1078. if (blocked) {
  1079. classes += config.bl ? ' bl_hidden' : ' bl';
  1080. remove = true;
  1081. }
  1082.  
  1083. if (included) {
  1084. classes += ' il';
  1085. _included(included, hit);
  1086. }
  1087. else {
  1088. classes += config.nl ? ' nl_hidden' : ' nl';
  1089. }
  1090.  
  1091. hit_html +=
  1092. '<div class="cont" style="margin-bottom: 2px;">' +
  1093. '<div class="' + classes + ' " style="overflow: hidden; white-space: nowrap; margin-bottom: 2px;">' +
  1094.  
  1095. '<div style="float: left; width: calc(100% - 330px);">' +
  1096.  
  1097. '<span style="width: 25%; float: left; display:inline-block; overflow: hidden;">' +
  1098. '<button data-term="' + hit.reqid + '" data-name="' + hit.reqname + '" class="rt">R</button>' +
  1099. '<button id="'+ hit.groupid + '" data-term="' + hit.safetitle + '" data-name="' + hit.safetitle + '" class="rt">T</button>' +
  1100. '<a href="' + hit.reqlink + '">' + hit.reqname + '</a>' +
  1101. '</span>' +
  1102.  
  1103. '<span style="width: 75%; float: right; display:inline-block; overflow: hidden;">' +
  1104. '<button value="' + hit.key + '" class="vb">vB</button>' +
  1105. '<button value="' + hit.key + '" class="irc">IRC</button>' +
  1106. '<a href="' + hit.prevlink + '">' + hit.title + '</a>' +
  1107. '</span>' +
  1108.  
  1109. '</div>' +
  1110.  
  1111. '<div style="float: right;">' +
  1112.  
  1113. '<span style="width: 60px; display:inline-block; text-align: center;">' +
  1114. hit.avail +
  1115. '</span>' +
  1116.  
  1117. '<span style="width: 60px; display:inline-block; text-align: center;">' +
  1118. '<a href="' + hit.pandlink + '">' + hit.reward + '</a>' +
  1119. '</span>' +
  1120.  
  1121. '<span class="to" style="width: 60px; display:inline-block; text-align: center;">' +
  1122. '<a href="' + hit.tvlink + '">' + hit.tv + '</a>' +
  1123. '</span>' +
  1124.  
  1125. '<span class="to" style="width: 60px; display:inline-block; text-align: center;">' +
  1126. '<a href="' + hit.tolink + '">' + hit.to.pay + '</a>' +
  1127. '</span>' +
  1128.  
  1129. '<span style="width: 60px; display:inline-block; text-align: center;">' +
  1130. '<button data-term="' + hit.groupid + '" data-reqid="' + hit.reqid + '" data-reqname="' + hit.reqname.replace(/"/g, "&quot;" ) + '" data-title="' + hit.safetitle + '" data-value="' + hit.reward.replace(/\$/g, '') + '" data-name="panda" class="pc">P</button>' +
  1131. '<button data-term="' + hit.groupid + '" data-reqid="' + hit.reqid + '" data-reqname="' + hit.reqname.replace(/"/g, "&quot;" ) + '" data-title="' + hit.safetitle + '" data-value="' + hit.reward.replace(/\$/g, '') + '" data-name="once" class="pc">O</button>' +
  1132. '</span>' +
  1133.  
  1134. '</div>' +
  1135. '</div>' +
  1136. '</div>'
  1137. ;
  1138.  
  1139. if (remove) {
  1140. var index = log_keys.indexOf(keys[i]);
  1141.  
  1142. if (index > -1) {
  1143. log_keys.splice(index, 1);
  1144. }
  1145. }
  1146. }
  1147.  
  1148. if (log_keys.length) {
  1149. for (var j = 0; j < log_keys.length; j ++) {
  1150. var hit_log = hitlog[log_keys[j]], included_log = _check_include(hit_log), rowcolor, classes_log, tvHourly;
  1151.  
  1152. rowcolor = hit_log.tv != 'N/A' ? _color_tv(hit_log) : _color_to(hit_log);
  1153.  
  1154. classes_log = rowcolor;
  1155.  
  1156. if (included_log) {
  1157. classes_log += ' il';
  1158. }
  1159. else {
  1160. classes_log += config.nl ? ' nl_hidden' : ' nl';
  1161. }
  1162.  
  1163. var quals = hit_log.quals.split(';');
  1164. var qualif = '';
  1165.  
  1166. for (var k = 0; k < quals.length; k ++) {
  1167. if (quals[k] !== '') {
  1168. if( quals[k].indexOf('~!~') != -1 ) {
  1169. var temp = quals[k].split('~!~');
  1170. quals[k] = temp[0];
  1171. if (temp[1].indexOf('request') == -1 ) {
  1172. //Qual test
  1173. quals[k] += '<form action="' +temp[1] +'" method="get" style=" display:inline!important;"><button>Take Test</button></form>';
  1174. }
  1175. else {
  1176. //Request Qual
  1177. //quals[k] += '<form action="' +temp[1] +'" method="post"><button>Request</button></form>';
  1178. }
  1179. }
  1180. qualif += '<li style="padding: 2px;">' + quals[k] + '</li>';
  1181. }
  1182. }
  1183.  
  1184.  
  1185.  
  1186. log_html +=
  1187. '<div class="cont loggid_' + hit_log.groupid +' logreqid_' + hit_log.reqid + '" style="margin-bottom: 2px;">' +
  1188. '<div class="' + classes_log + '" style="overflow: hidden; white-space: nowrap;">' +
  1189.  
  1190. '<div style="float: left;">' +
  1191. '<span style="width: 80px; display:inline-block;">' +
  1192. '<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>' +
  1193. timeis[0] + ':' + timeis[1] + timeis[3] + '</span>' +
  1194. '</div>' +
  1195.  
  1196. '<div style="float: left; width: calc(100% - 410px);">' +
  1197.  
  1198. '<span style="width: 25%; float: left; display:inline-block; overflow: hidden;">' +
  1199. '<button data-term="' + hit_log.reqid + '" data-name="' + hit_log.reqname + '" class="rt">R</button>' +
  1200. '<button id="'+ hit_log.groupid + '" data-term="' + hit_log.safetitle + '" data-name="' + hit_log.safetitle + '" class="rt">T</button>' +
  1201. '<a href="' + hit_log.reqlink + '">' + hit_log.reqname + '</a>' +
  1202. '</span>' +
  1203.  
  1204. '<span style="width: 75%; float: right; display:inline-block; overflow: hidden;">' +
  1205. '<button value="' + hit_log.key + '" class="vb">vB</button>' +
  1206. '<button value="' + hit_log.key + '" class="irc">IRC</button>' +
  1207. '<a href="' + hit_log.prevlink + '">' + hit_log.title + '</a>' +
  1208. '</span>' +
  1209.  
  1210. '</div>' +
  1211.  
  1212. '<div style="float: right;">' +
  1213.  
  1214. '<span style="width: 60px; display:inline-block; text-align: center;">' +
  1215. hit_log.avail +
  1216. '</span>' +
  1217.  
  1218. '<span style="width: 60px; display: inline-block; text-align: center;">' +
  1219. '<a href="' + hit_log.pandlink + '">' + hit_log.reward + '</a>' +
  1220. '</span>' +
  1221.  
  1222. '<span class="to" style="width: 60px; display:inline-block; text-align: center;">' +
  1223. '<a href="' + hit_log.tvlink + '">' + hit_log.tv + '</a>' +
  1224. '</span>' +
  1225.  
  1226.  
  1227. '<span class="to" style="width: 60px; display:inline-block; text-align: center;">' +
  1228. '<a href="' + hit_log.tolink + '">' + hit_log.to.pay + '</a>' +
  1229. '</span>' +
  1230.  
  1231. '<span style="width: 60px; display:inline-block; text-align: center;">' +
  1232. '<button data-term="' + hit_log.groupid + '" data-reqid="' + hit_log.reqid + '" data-reqname="' + hit_log.reqname.replace(/"/g, "&quot;" ) + '" data-title="' + hit_log.safetitle + '" data-value="' + hit_log.reward.replace(/\$/g, '') + '" data-name="panda" class="pc">P</button>' +
  1233. '<button data-term="' + hit_log.groupid + '" data-reqid="' + hit_log.reqid + '" data-reqname="' + hit_log.reqname.replace(/"/g, "&quot;" ) + '" data-title="' + hit_log.safetitle + '" data-value="' + hit_log.reward.replace(/\$/g, '') + '" data-name="once" class="pc">O</button>' +
  1234. '</span>' +
  1235.  
  1236. '</div>' +
  1237. '</div>'+
  1238.  
  1239. '<div class="info ' + rowcolor + '" value="' + hit_log.key + '" style="overflow: hidden; display: none; font-size: 11px;">' +
  1240.  
  1241. '<div style="border-bottom: 1px solid #000000;"></div>' +
  1242.  
  1243. '<span style="width: 33%; float: left; display:inline-block; padding: 5px;">' +
  1244. '<span style="text-decoration: underline;">Description</span>' +
  1245. '<div style="padding: 2px;">' + hit_log.desc +'</div>' +
  1246. '<span style="text-decoration: underline;">Time</span>' +
  1247. '<div style="padding: 2px;">' + hit_log.time +'</div>' +
  1248. '</span>' +
  1249.  
  1250. '<span style="width: 33%; float: left; display:inline-block; padding: 5px;">' +
  1251. '<span style="text-decoration: underline;">Qualifications</span>' +
  1252. qualif +
  1253. '</span>' +
  1254.  
  1255. '<span style="width: calc(34% - 30px); float: right; display:inline-block; padding: 5px;">' +
  1256. '<span style="text-decoration: underline;">Turkopticon</span>' +
  1257. '<br>' +
  1258. '<span style="width: 70px; display:inline-block; padding: 2px;">Pay : ' + hit_log.to.pay +'</span>' +
  1259. '<span style="width: 70px; display:inline-block; padding: 2px;">Fair : ' + hit_log.to.fair +'</span>' +
  1260. '<br>' +
  1261. '<span style="width: 70px; display:inline-block; padding: 2px;">Comm : ' + hit_log.to.comm +'</span>' +
  1262. '<span style="width: 70px; display:inline-block; padding: 2px;">Fast : ' + hit_log.to.fast +'</span>' +
  1263. '</span>' +
  1264.  
  1265. '</div>' +
  1266. '</div>';
  1267.  
  1268. logged ++;
  1269. }
  1270. if (config.new) {
  1271. _sound('new');
  1272. }
  1273. }
  1274. $('#new_hits_').html(hit_html);
  1275. $('#log_hits_').prepend(log_html);
  1276.  
  1277. searches ++;
  1278. var hits_data = '<span> ' + timeis[0] + ':' + timeis[1] + ':' + timeis[2] + timeis[3] + ' Scanned HITs: ' + keys.length + '</span><span style="float: right;">' + searches + '</span>';
  1279. var logged_hits_data = '<span style="float: right;">' + logged + '</span>';
  1280.  
  1281. $('#hits_data').html(hits_data);
  1282. $('#logged_hits_data').html(logged_hits_data);
  1283.  
  1284. if ($('#scan_button').text() === 'Stop') {
  1285. setTimeout(function () {
  1286. _scan();
  1287. }, $('#delay').val() * 1000);
  1288. }
  1289. }
  1290.  
  1291. function _sound (sound) {
  1292. if (sound === 'new') { $('#audio_' + config.newaudio) [0].play(); }
  1293. if (sound === 'include') { $('#audio_' + config.newaudio) [0].play(); }
  1294. if (sound === 'il') { $('#audio_' + $('#il_sound').val()) [0].play(); }
  1295. if (sound === 'il_edit') { $('#audio_' + $('#edit_il_sound').val()) [0].play(); }
  1296. }
  1297.  
  1298. function _check_block (hit) {
  1299. for (var key in blocklist) {
  1300. var obj = blocklist[key];
  1301. 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()) {
  1302. return obj;
  1303. }
  1304. }
  1305. }
  1306.  
  1307. function _check_include (hit) {
  1308. for (var key in includelist) {
  1309. var obj = includelist[key];
  1310. 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()) {
  1311. return obj;
  1312. }
  1313. }
  1314. }
  1315.  
  1316. function _included (obj, hit) {
  1317. var check = noti_delay.indexOf(hit.key) !== -1;
  1318. var pushcheck = push_delay.indexOf(hit.key) !== -1;
  1319.  
  1320. if (!check) {
  1321. noti_delay.unshift(hit.key);
  1322. setTimeout(function () { noti_delay.pop(); }, config.alert * 1000);
  1323. }
  1324. if (obj.noti_cb && !check) {
  1325. Notification.requestPermission();
  1326. var n = new Notification(hit.reqname + ' | ' + hit.reward, {
  1327. icon : 'http://nopurpose.org/stuff/avatars/Lj21396.gif',
  1328. body : hit.title,
  1329. });
  1330. setTimeout(n.close.bind(n), 5000);
  1331.  
  1332. n.onclick = function(e) {
  1333. e.preventDefault();
  1334. window.open(hit.prevlink, '_blank');
  1335. };
  1336.  
  1337. }
  1338. if (obj.sound_cb && !check) {
  1339. $('#audio_' + obj.sound)[0].play();
  1340. }
  1341. if (obj.push_cb && !pushcheck && config.pb) {
  1342. push_delay.unshift(hit.key);
  1343. setTimeout(function () { push_delay.pop(); }, 900000);
  1344.  
  1345. var push = {};
  1346.  
  1347. push['type'] = 'note';
  1348. push['title'] = 'HIT Finder';
  1349. push['body'] = '[' + hit.reqname + ']\n[' + hit.title + ']\n[' + hit.reward + ']\n[' + hit.prevlink + ']';
  1350.  
  1351. $.ajax({
  1352. type : 'POST',
  1353. headers : {'Authorization': 'Bearer ' + config.push},
  1354. url : 'https://api.pushbullet.com/v2/pushes',
  1355. data : push
  1356. });
  1357.  
  1358. }
  1359. }
  1360.  
  1361. function _color_tv(hit) {
  1362. var tvHourly = hit.tv.replace(/\$/g, '');
  1363.  
  1364. if (config.theme == "light") {
  1365. if (tvHourly >= 10.00) { return 'tvHigh'; }
  1366. else if (tvHourly >= 7.25) { return 'tvFair'; }
  1367. else { return 'tvLow'; }
  1368. }
  1369. else {
  1370. if (tvHourly >= 10.00) { return 'toHigh'; }
  1371. else if (tvHourly >= 7.25) { return 'toAverage'; }
  1372. else { return 'toLow'; }
  1373.  
  1374. }
  1375. }
  1376.  
  1377. function _color_to (hit) {
  1378. var to = hit.to.pay;
  1379.  
  1380. if (config.theme == "light") {
  1381. if (to > 4) { return 'tvHigh'; }
  1382. else if (to > 2.5) { return 'tvFair'; }
  1383. else if (to > 0) { return 'tvLow'; }
  1384. else { return 'tvNone'; }
  1385. }
  1386. else {
  1387. if (to > 4) { return 'toHigh'; }
  1388. else if (to > 3) { return 'toGood'; }
  1389. else if (to > 2) { return 'toAverage'; }
  1390. else if (to > 1) { return 'toLow'; }
  1391. else if (to > 0) { return 'toPoor'; }
  1392. else { return 'toNone'; }
  1393.  
  1394. }
  1395. }
  1396.  
  1397. function _convert_seconds (seconds) {
  1398. seconds = Number(seconds);
  1399. var h = Math.floor(seconds / 3600);
  1400. var m = Math.floor(seconds % 3600 / 60);
  1401. var s = Math.floor(seconds % 3600 % 60);
  1402. var time = '';
  1403. if (h > 0) { time += h + ' hour(s) '; }
  1404. if (m > 0) { time += m + ' minutes(s) '; }
  1405. if (s > 0) { time += s + ' seconds(s)'; }
  1406. return time;
  1407. }
  1408.  
  1409. function _block (term, name, gid) {
  1410. $('#bl_term') .val(term);
  1411. $('#bl_name') .val(name);
  1412. $('#bl_gid').val(gid);
  1413. $('#bl') .show();
  1414. }
  1415.  
  1416. function _panda(term, reqname, reqid, title, value, name, button) {
  1417. var hitData = {
  1418. hitTitle: title,
  1419. requesterName: reqname,
  1420. requesterId: reqid,
  1421. hitValue: value
  1422. }
  1423. var once = name == "panda" ? false : true;
  1424.  
  1425. PandaCrazy.online().then (
  1426. function(successResp) {
  1427. PandaCrazy.addJob( term, once, hitData );
  1428. button.addClass("clicked")
  1429. },
  1430. function(failedResp) {
  1431. 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");
  1432. }
  1433. );
  1434. //console.log ( running );
  1435. }
  1436.  
  1437.  
  1438. function _add_block (obj) {
  1439. if (!blocklist[obj.term]) {
  1440. blocklist[obj.term] = obj;
  1441. _init_lists();
  1442. }
  1443. }
  1444.  
  1445. function _edit_block (term) {
  1446. var obj = blocklist[term];
  1447. $('#edit_bl_term') .val(obj.term) .text(obj.term);
  1448. $('#edit_bl_name') .val(obj.name);
  1449. $('#edit_bl_save') .val(obj.term);
  1450. $('#edit_bl_delete') .val(obj.term);
  1451. $('#edit_bl') .show();
  1452. }
  1453.  
  1454. function _update_block (block) {
  1455. var obj = blocklist[block];
  1456. obj.name = $('#edit_bl_name').val();
  1457. _init_lists();
  1458. }
  1459.  
  1460. function _delete_block (block) {
  1461. delete blocklist[block];
  1462. _init_lists();
  1463. }
  1464.  
  1465. function _add_include (obj) {
  1466. if (!includelist[obj.term]) {
  1467. includelist[obj.term] = obj;
  1468. _init_lists();
  1469. }
  1470. }
  1471.  
  1472. function _edit_include (term) {
  1473. var obj = includelist[term];
  1474.  
  1475. $('#edit_il_term') .val(obj.term) .text(obj.term);
  1476. $('#edit_il_name') .val(obj.name);
  1477. $('#edit_il_sound') .val(obj.sound);
  1478.  
  1479. $('#edit_il_noti_cb') .prop('checked', obj.noti_cb);
  1480. $('#edit_il_sound_cb') .prop('checked', obj.sound_cb);
  1481. $('#edit_il_push_cb') .prop('checked', obj.push_cb);
  1482.  
  1483. $('#edit_il_save') .val(obj.term);
  1484. $('#edit_il_delete') .val(obj.term);
  1485.  
  1486. $('#edit_il').show();
  1487. }
  1488.  
  1489. function _update_include (term) {
  1490. var obj = includelist[term];
  1491. obj.name = $('#edit_il_name') .val().trim();
  1492. obj.sound = $('#edit_il_sound') .val().trim();
  1493. obj.noti_cb = $('#edit_il_noti_cb') .prop('checked');
  1494. obj.sound_cb = $('#edit_il_sound_cb') .prop('checked');
  1495. obj.push_cb = $('#edit_il_push_cb') .prop('checked');
  1496. _init_lists();
  1497. }
  1498.  
  1499. function _delete_include (term) {
  1500. delete includelist[term];
  1501. _init_lists();
  1502. }
  1503.  
  1504. function _hide_hit_list( hide ) {
  1505. if (hide) {
  1506. $("#hits_button").text('Show New HITs');
  1507. $('#hits_table').hide();
  1508. $('#hits_hidden').show();
  1509. config.h_hidden = '1';
  1510. }
  1511. else {
  1512. $("#hits_button").text('Hide New HITs');
  1513. $('#hits_table').show();
  1514. $('#hits_hidden').hide();
  1515. config.h_hidden = '0';
  1516. }
  1517.  
  1518. _save( 'showhide' );
  1519. }
  1520.  
  1521. function _hide_log_list( hide ) {
  1522. if (hide) {
  1523. $("#logg_button").text('Show Logged HITs');
  1524. $('#log_table').hide();
  1525. $('#log_hidden').show();
  1526. config.l_hidden = '1';
  1527. }
  1528. else {
  1529. $("#logg_button").text('Hide Logged HITs');
  1530. $('#log_table').show();
  1531. $('#log_hidden').hide();
  1532. config.l_hidden = '0';
  1533. }
  1534.  
  1535. _save( 'showhide' );
  1536. }
  1537.  
  1538. function _init_lists () {
  1539. var bl_sort = [], il_sort = [], bl_html = '', il_html = '';
  1540.  
  1541. for (var bl_key in blocklist) {
  1542. bl_sort.push([bl_key, blocklist[bl_key].name]);
  1543. }
  1544.  
  1545. bl_sort.sort(function (a, b) {
  1546. if (a[1].toLowerCase() < b[1].toLowerCase()) return -1;
  1547. if (a[1].toLowerCase() > b[1].toLowerCase()) return 1;
  1548. return 0;
  1549. });
  1550.  
  1551. for (var i = 0; i < bl_sort.length; i ++) {
  1552. var bl_obj = blocklist[bl_sort[i][0]];
  1553. bl_html += '<button class="blockit" style="margin: 2px;" value="' + bl_obj.term + '" title="' + bl_obj.term + '">' + bl_obj.name + '</button>';
  1554. }
  1555.  
  1556. for (var il_key in includelist) {
  1557. il_sort.push([il_key, includelist[il_key].name]);
  1558. }
  1559.  
  1560. il_sort.sort(function (a, b) {
  1561. if (a[1].toLowerCase() < b[1].toLowerCase()) return -1;
  1562. if (a[1].toLowerCase() > b[1].toLowerCase()) return 1;
  1563. return 0;
  1564. });
  1565.  
  1566. for (var j = 0; j < il_sort.length; j ++) {
  1567. var il_obj = includelist[il_sort[j][0]];
  1568. il_html += '<button class="includeit" style="margin: 2px;" value="' + il_obj.term + '" title="' + il_obj.term + '">' + il_obj.name + '</button>';
  1569. }
  1570.  
  1571. $('#bl_items') .html(bl_html);
  1572. $('#il_items') .html(il_html);
  1573. _save('init');
  1574. }
  1575.  
  1576. function _import_block () {
  1577. var import_bl = prompt(
  1578. 'Block List Import\n\n' +
  1579. 'You can import from HIT Finder or HIT Scraper.\n\n' +
  1580. 'This will not delete your current block list, only add to it.\n\n' +
  1581. 'Please enter your block list here.',
  1582. ''
  1583. );
  1584.  
  1585. if (import_bl) {
  1586. var json = _json_validator(import_bl);
  1587.  
  1588. if (json) {
  1589. var _bl_obj = JSON.parse(import_bl);
  1590. for (var key in _bl_obj) {
  1591. if (_bl_obj[key].hasOwnProperty('term') && _bl_obj[key].hasOwnProperty('name') && !_bl_obj[key].hasOwnProperty('sound')) {
  1592. if (!blocklist[key]) {
  1593. blocklist[key] = {
  1594. term : _bl_obj[key].term,
  1595. name : _bl_obj[key].name
  1596. };
  1597. }
  1598. }
  1599. else {
  1600. alert('An error occured while importing.\n\n Please check if you have a valid import and try again.');
  1601. break;
  1602. }
  1603. }
  1604. _init_lists();
  1605. }
  1606. else if (import_bl.match(/^/)) {
  1607. var _bl_arr = import_bl.trim().split('^');
  1608. for (var i = 0; i < _bl_arr.length; i ++) {
  1609. if (!blocklist[_bl_arr[i]]) {
  1610. blocklist[_bl_arr[i]] = {
  1611. term : _bl_arr[i],
  1612. name : _bl_arr[i]
  1613. };
  1614. }
  1615. }
  1616. _init_lists();
  1617. }
  1618. }
  1619. else {
  1620. alert('An error occured while importing.\n\n Please check if you have a valid import and try again.');
  1621. }
  1622. }
  1623.  
  1624. function _export_block () {
  1625. GM_setClipboard(localStorage.getItem('_finder_bl'));
  1626. alert('Your block list has been copied to your clipboard.');
  1627. }
  1628.  
  1629. function _import_include () {
  1630. var import_il = prompt(
  1631. 'Include List Import\n\n' +
  1632. 'You can import from HIT Finder or HIT Scraper.\n\n' +
  1633. 'This will not delete your current include list, only add to it.\n\n' +
  1634. 'Please enter your include list here.',
  1635. ''
  1636. );
  1637.  
  1638. if (import_il) {
  1639. var json = _json_validator(import_il);
  1640.  
  1641. if (json) {
  1642. var _il_obj = JSON.parse(import_il);
  1643.  
  1644. for (var key in _il_obj) {
  1645. if (_il_obj[key].hasOwnProperty('term') && _il_obj[key].hasOwnProperty('name') && _il_obj[key].hasOwnProperty('sound')) {
  1646. if (!includelist[key]) {
  1647. includelist[key] = {
  1648. term : _il_obj[key].term,
  1649. name : _il_obj[key].name,
  1650. sound : _il_obj[key].sound,
  1651. noti_cb : _il_obj[key].noti_cb,
  1652. sound_cb : _il_obj[key].sound_cb,
  1653. push_cb : _il_obj[key].push_cb
  1654. };
  1655. }
  1656. }
  1657. else {
  1658. alert('An error occured while importing.\n\n Please check that you have a valid import and try again.');
  1659. break;
  1660. }
  1661. }
  1662. _init_lists();
  1663. }
  1664. else if (import_il.match(/^/)) {
  1665. var _il_arr = import_il.split('^');
  1666.  
  1667. for (var i = 0; i < _il_arr.length; i ++) {
  1668. if (!includelist[_il_arr[i]]) {
  1669. includelist[_il_arr[i]] = {
  1670. term : _il_arr[i],
  1671. name : _il_arr[i],
  1672. sound : '1',
  1673. noti_cb : true,
  1674. sound_cb : true,
  1675. push_cb : false
  1676. };
  1677. }
  1678. }
  1679. _init_lists();
  1680. }
  1681. }
  1682. else {
  1683. alert('An error occured while importing.\n\n Please check that you have a valid import and try again.');
  1684. }
  1685. }
  1686.  
  1687. function _export_include () {
  1688. GM_setClipboard(localStorage.getItem('_finder_il'));
  1689. alert('Your include list has been copied to your clipboard.');
  1690. }
  1691.  
  1692. function _export_vb (key) {
  1693. var hit = hitlog[key];
  1694.  
  1695. var pay = hit.to.pay, _pay = '#B30000';
  1696. if (pay > 3.99) { _pay = '#00B300'; }
  1697. else if (pay > 2.99) { _pay = '#B3B300'; }
  1698. else if (pay > 1.99) { _pay = '#B37400'; }
  1699.  
  1700. var fair = hit.to.fair, _fair = '#B30000';
  1701. if (fair > 3.99) { _fair = '#00B300'; }
  1702. else if (fair > 2.99) { _fair = '#B3B300'; }
  1703. else if (fair > 1.99) { _fair = '#B37400'; }
  1704.  
  1705. var comm = hit.to.comm, _comm = '#B30000';
  1706. if (comm > 3.99) { _comm = '#00B300'; }
  1707. else if (comm > 2.99) { _comm = '#B3B300'; }
  1708. else if (comm > 1.99) { _comm = '#B37400'; }
  1709.  
  1710. var fast = hit.to.fast, _fast = '#B30000';
  1711. if (fast > 3.99) { _fast = '#00B300'; }
  1712. else if (fast > 2.99) { _fast = '#B3B300'; }
  1713. else if (fast > 1.99) { _fast = '#B37400'; }
  1714.  
  1715. var tv = hit.tv.replace(/\$/g, ''), _tvhourly = '#B30000';
  1716. if ( tv != 'N/A' ) {
  1717. if ( tv >= 10 ) { _tvhourly = '#00B300'; }
  1718. else if ( tv >= 7.25 ) { _tvhourly = '#B3B300'; }
  1719. tv = '$' + tv + '/hr';
  1720. }
  1721.  
  1722. var quals = hit.quals.split(';');
  1723. var qualif = '';
  1724.  
  1725. for (var k = 0; k < quals.length; k ++) {
  1726. if (quals[k] !== '') {
  1727. if( quals[k].indexOf('~!~') != -1 ) {
  1728. var temp = quals[k].split('~!~');
  1729. quals[k] = temp[0];
  1730. if (temp[1].indexOf('request') == -1 ) {
  1731. //Qual test
  1732. quals[k] += '[URL=' +temp[1] +']Take Test[/URL]';
  1733. }
  1734. else {
  1735. //Request Qual
  1736. //quals[k] += '<form action="' +temp[1] +'" method="post"><button>Request</button></form>';
  1737. }
  1738. }
  1739. qualif += quals[k] + ';';
  1740. }
  1741. }
  1742.  
  1743. var exportcode = '[table][tr][td]'+
  1744. '[b]Title:[/b] [URL=' + pandaurl + hit.prevlink + ']' + hit.title + '[/URL] | [URL=' + pandaurl + hit.pandlink + ']PANDA[/URL]\n' +
  1745. '[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' +
  1746. '([URL='+hit.tolink+']TO[/URL]):'+
  1747. '[b] \[Pay: [COLOR=' + _pay + ']' + pay + '[/COLOR]\][/b]'+
  1748. '[b] \[Fair: [COLOR=' + _fair + ']' + fair + '[/COLOR]\][/b]' +
  1749. '[b] \[Comm: [COLOR=' + _comm +']' + comm + '[/COLOR]\][/b]' +
  1750. '[b] \[Fast: [COLOR=' + _fast + ']' + fast + '[/COLOR]\][/b]\n' +
  1751. '[b]Description:[/b] ' + hit.desc + '\n' +
  1752. '[b]Time:[/b] ' + hit.time + '\n' +
  1753. '[b]HITs Available:[/b] ' + hit.avail + '\n' +
  1754. '[b]Reward:[/b] [COLOR=green][b] ' + hit.reward + '[/b][/COLOR]\n' +
  1755. '[b]Qualifications:[/b] ' + qualif + '\n' +
  1756. '[/td][/tr][/table]';
  1757.  
  1758. GM_setClipboard(exportcode);
  1759. alert('Forum export has been copied to your clipboard.');
  1760. }
  1761.  
  1762. function _export_irc (key) {
  1763. var hit = hitlog[key];
  1764.  
  1765. $.get('https://ns4t.net/yourls-api.php?action=bulkshortener&title=MTurk&signature=39f6cf4959&urls[]=' + hit.prevlink + '&urls[]=' + hit.pandlink, function (data) {
  1766. var urls = data.split(';'),
  1767. preview = urls[0],
  1768. panda = urls[1];
  1769.  
  1770. var exportcode = 'Req: ' + hit.reqname + ' ■ Title: ' + hit.title + ' ■ Reward: ' + hit.reward;
  1771. exportcode += preview !== panda ? ' ■ Prev: ' + preview + ' ■ PandA: '+ panda : ' ■ Search: ' + preview;
  1772. exportcode += ' ■ TO: (Pay: ' + hit.to.pay + ') (Fair: ' + hit.to.fair + ') (Comm: ' + hit.to.comm + ') (Fast: ' + hit.to.fast + ')';
  1773.  
  1774. GM_setClipboard(exportcode);
  1775. alert('IRC export has been copied to your clipboard.');
  1776.  
  1777. }).fail(function () {
  1778. alert('Failed to shorten links.');
  1779. });
  1780. }
  1781.  
  1782. function _json_validator (data) {
  1783. try {
  1784. JSON.parse(data);
  1785. return true;
  1786. }
  1787. catch (e) {
  1788. return false;
  1789. }
  1790. }
  1791.  
  1792. function _save (type) {
  1793. if (type !== 'init' && type !== 'custom') {
  1794. config.delay = $('#delay') .val();
  1795. config.rew = $('#min_rew') .val();
  1796. config.avail = $('#min_avail') .val();
  1797. config.mto = $('#min_to') .val();
  1798. config.alert = $('#alert_delay') .val();
  1799. config.type = $('#type') .val();
  1800. config.size = $('#size') .val();
  1801. config.newaudio = $('#new_audio') .val();
  1802. config.theme = $('#adv_theme') .val();
  1803. config.to_theme = $('#to_theme') .val();
  1804.  
  1805. config.new = $('#new_sound') .prop('checked');
  1806. config.pb = $('#pb') .prop('checked');
  1807. config.to = $('#to') .prop('checked');
  1808. config.qual = $('#qual') .prop('checked');
  1809. config.nl = $('#nl_hide') .prop('checked');
  1810. config.bl = $('#bl_hide') .prop('checked');
  1811. config.m = $('#m_hide') .prop('checked');
  1812. console.log($('#push').val());
  1813.  
  1814. }
  1815. if (type === 'custom' && $('#adv_theme').val() === 'custom') {
  1816. config.custom = {
  1817. main : $('#theme_main') .val(),
  1818. primary : $('#theme_primary') .val(),
  1819. secondary : $('#theme_secondary') .val(),
  1820. text : $('#theme_text') .val(),
  1821. link : $('#theme_link') .val(),
  1822. visited : $('#theme_visited') .val(),
  1823. prop : false
  1824. };
  1825. themes.custom = config.custom;
  1826. }
  1827. config.push = $('#push').val();
  1828.  
  1829. localStorage.setItem('_finder', JSON.stringify(config));
  1830. localStorage.setItem('_finder_bl', JSON.stringify(blocklist));
  1831. localStorage.setItem('_finder_il', JSON.stringify(includelist));
  1832.  
  1833. if (config.nl) { $('.nl').toggleClass('nl nl_hidden'); }
  1834. else { $('.nl_hidden').toggleClass('nl nl_hidden'); }
  1835.  
  1836. if (config.bl) { $('.bl').toggleClass('bl bl_hidden'); }
  1837. else { $('.bl_hidden').toggleClass('bl bl_hidden'); }
  1838.  
  1839. if (config.m) { $('.m').toggleClass('m m_hidden'); }
  1840. else { $('.m_hidden').toggleClass('m m_hidden'); }
  1841. }
  1842.  
  1843. function _theme () {
  1844. var theme = themes[config.theme];
  1845.  
  1846. $('#theme_main') .val(theme.main) .prop('disabled', theme.prop);
  1847. $('#theme_primary') .val(theme.primary) .prop('disabled', theme.prop);
  1848. $('#theme_secondary') .val(theme.secondary) .prop('disabled', theme.prop);
  1849. $('#theme_text') .val(theme.text) .prop('disabled', theme.prop);
  1850. $('#theme_link') .val(theme.link) .prop('disabled', theme.prop);
  1851. $('#theme_visited') .val(theme.visited) .prop('disabled', theme.prop);
  1852. _write_theme();
  1853. }
  1854.  
  1855. function _write_theme () {
  1856. var css = _to_theme(), theme = themes[config.theme];
  1857.  
  1858. css +=
  1859. 'html {color: #' + theme.text + '; background-color: #' + theme.main + '; line-height: 1.5; font-family: "Roboto", sans-serif; font-size: 15px; font-weight: normal;}' +
  1860. 'body {margin: 0px;}' +
  1861. '#menubar { background-color: #' + theme.menu + '; margin: 0px; padding: 3px; height:30px; color: #' + theme.menutext + ' }' +
  1862. '#latest_hits { margin: 5px; }' +
  1863. '#logged_hits { margin: 5px; }' +
  1864. '#config { background-color: #' + theme.primary + '; border: 2px #' + theme.text + ' solid; padding: 2px;}' +
  1865.  
  1866. '#bl_items, #il_items {background-color: #'+theme.main+'; height: calc(100% - 64px); overflow-y: scroll;}' +
  1867. '#bl_div, #il_div {background-color: #'+theme.primary+'; border: 2px solid #'+theme.secondary+';}' +
  1868.  
  1869. '.add {background-color: #'+theme.primary+'; border: 2px solid #'+theme.secondary+';}' +
  1870.  
  1871. '.bl {border: 2px solid #FF0000;}' +
  1872. '.il {border: 2px solid #009900;}' +
  1873. '.hidden, .nl_hidden, .bl_hidden, .m_hidden {display: none;}' +
  1874. 'button:focus {outline: none !important;}';
  1875.  
  1876. if (config.theme == 'light' ) {
  1877. css +=
  1878. '.tvHigh {background-color: rgba(0,128,0,0.3); }' +
  1879. '.tvFair {background-color: rgba(255,165, 0, 0.3);}' +
  1880. '.tvLow {background-color: rgba(255,0,0,0.3); }' +
  1881. '.tvNone {background-color: rgba(128,128,128, 0.3); }'
  1882. }
  1883.  
  1884. $('#css').html(css);
  1885. }
  1886.  
  1887. function _to_theme () {
  1888. var to, theme = themes[config.theme], color = '';
  1889. console.log(config.to_theme);
  1890. if (config.theme === 'default') {
  1891. color = 'd9d9d9';
  1892. }
  1893. else {
  1894. color = '262626';
  1895. }
  1896.  
  1897. switch (config.to_theme) {
  1898. case '1':
  1899. to =
  1900. 'td {font-weight: bold;}' +
  1901. '.cont, .hit, .details {color: #000000;}' +
  1902. '.toHigh {background-color: #33cc59;}' +
  1903. '.toGood {background-color: #a6cc33;}' +
  1904. '.toAverage {background-color: #cccc33;}' +
  1905. '.toLow {background-color: #cca633;}' +
  1906. '.toPoor {background-color: #cc3333;}' +
  1907. '.toNone {background-color: #cccccc;}' +
  1908. '.rt, .pc {width: 20px; height: 20px; background-color: transparent; margin: 1px; border: 1px solid #000000; font-size: 80%; padding: 1px;}' +
  1909. '.vb, .irc {width: 25px; height: 20px; background-color: transparent; margin: 1px; border: 1px solid #000000; font-size: 80%; padding: 1px;}' +
  1910. '.clicked {background-color:grey;}';
  1911. ;
  1912. return to;
  1913. case '2':
  1914. to =
  1915. 'a {color: #'+theme.link+';}' +
  1916. 'a:visited {color: #'+theme.visited+';}' +
  1917. 'tbody td {color: #'+theme.text+';}' +
  1918. '.to a {color: #000000;}' +
  1919.  
  1920. '.cont, .details {color: #'+theme.text+';}' +
  1921. '.toHigh {background-color: #'+color+';}' +
  1922. '.toGood {background-color: #'+color+';}' +
  1923. '.toAverage {background-color: #'+color+';}' +
  1924. '.toLow {background-color: #'+color+';}' +
  1925. '.toPoor {background-color: #'+color+';}' +
  1926. '.toNone {background-color: #'+color+';}' +
  1927.  
  1928. '.toHigh .to {background-color: #33cc59;}' +
  1929. '.toGood .to {background-color: #a6cc33;}' +
  1930. '.toAverage .to {background-color: #cccc33;}' +
  1931. '.toLow .to {background-color: #cca633;}' +
  1932. '.toPoor .to {background-color: #cc3333;}' +
  1933. '.toNone .to {background-color: #cccccc;}' +
  1934. '.rt, .pc {width: 20px; height: 20px; color: #'+theme.text+'; background-color: transparent; margin: 1px; border: 1px solid #'+theme.text+'; font-size: 80%; padding: 1px;}' +
  1935. '.vb, .irc {width: 25px; height: 20px; color: #'+theme.text+'; background-color: transparent; margin: 1px; border: 1px solid #'+theme.text+'; font-size: 80%; padding: 1px;}' +
  1936. '.clicked {background-color:grey;}';
  1937. ;
  1938. return to;
  1939. case '3':
  1940. to =
  1941. 'a {color: #'+theme.link+';}' +
  1942. 'a:visited {color: #'+theme.visited+';}' +
  1943. 'tbody td {color: #'+theme.text+';}' +
  1944.  
  1945. '.cont, .details {color: #'+theme.text+';}' +
  1946. '.toHigh {background-color: #'+color+';}' +
  1947. '.toGood {background-color: #'+color+';}' +
  1948. '.toAverage {background-color: #'+color+';}' +
  1949. '.toLow {background-color: #'+color+';}' +
  1950. '.toPoor {background-color: #'+color+';}' +
  1951. '.toNone {background-color: #'+color+';}' +
  1952.  
  1953. '.toHigh .to a {color: #33cc59;}' +
  1954. '.toGood .to a {color: #a6cc33;}' +
  1955. '.toAverage .to a {color: #cccc33;}' +
  1956. '.toLow .to a {color: #cca633;}' +
  1957. '.toPoor .to a {color: #cc3333;}' +
  1958. '.toNone .to a {color: #cccccc;}' +
  1959. '.rt, .pc {width: 20px; height: 20px; color: #'+theme.text+'; background-color: transparent; margin: 1px; border: 1px solid #'+theme.text+'; font-size: 80%; padding: 1px;}' +
  1960. '.vb, .irc {width: 25px; height: 20px; color: #'+theme.text+'; background-color: transparent; margin: 1px; border: 1px solid #'+theme.text+'; font-size: 80%; padding: 1px;}' +
  1961. '.clicked {background-color:grey;}';
  1962. ;
  1963. return to;
  1964. }
  1965. }
  1966.  
  1967. $('#type option[value="' + config.type + '"]') .prop('selected', true);
  1968. $('#size option[value="' + config.size + '"]') .prop('selected', true);
  1969. $('#new_audio option[value="' + config.newaudio + '"]') .prop('selected', true);
  1970. $('#adv_theme option[value="' + config.theme + '"]') .prop('selected', true);
  1971. $('#to_theme option[value="' + config.to_theme + '"]') .prop('selected', true);
  1972.  
  1973. _theme();
  1974. _init_lists();
  1975. _hide_hit_list( config.h_hidden == '1' ? true : false );
  1976. _hide_log_list( config.l_hidden == '1' ? true : false );

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址