您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Add your projected earnings to whatever sites you want. Uses Task Archive's API.
// ==UserScript== // @name [Worker] Today's Projected Earnings (mTurk) // @version 1.2 // @description Add your projected earnings to whatever sites you want. Uses Task Archive's API. // @author red_rum97 // @include http://www.mturkcrowd.com/* // @include https://*.mturk.com/* // @exclude https://worker.mturk.com/* // @noframes // @grant GM_getValue // @grant GM_setValue // @run-at document-end // @namespace https://greasyfork.org/users/162707 // ==/UserScript== /* jshint esversion: 6 */ // 1. Change the '@include' above to whatever site(s) you want. // 2. Change or add stuff to the 'elementStyle' below if you want. // 3. IMPORTANT: Turn on TA's API for the @include site(s) so the script can get // your earnings and update whenever you submit a HIT or one gets rejected. // Instructions here: chrome-extension://boaodomjkjehcobmcehliafmodimcidg/html/documentation.html#faq=1_45 // // I threw this script together while playing around with TA's API for // an idea I have in a larger script that I've been working on. I won't // have much time to make any major changes to it anytime soon. const elementStyle = { // position: 'absolute', position: 'fixed', // top: '0px', // right: '0px', bottom: '0px', left: '0px', fontSize: '16px', fontWeight: 'bold', color: 'black', backgroundColor: 'white', border: 'solid 1px', borderRadius: '2px', borderColor: 'forestgreen', padding: '2px 8px', margin: '10px', cursor: 'default', zIndex: 10000 }; // ------------------------------------------ (async () => { const element = document.createElement('div'); const today = () => new Intl.DateTimeFormat('en-US', { day: '2-digit', month: '2-digit', year: 'numeric', timeZone: 'America/Los_Angeles' }).format(new Date) .replace(/(\d+)\/(\d+)\/(\d+)/, '$3$1$2'); const update = async () => { let disconnect; const messageId = Math.random() + ''; const queryEarnings = () => { window.postMessage({ id: messageId, destination: 'TaskArchive', fields: 'monetary_reward', searchTasks: { state: ['pending', 'approved'], date: today() }}, document.location.origin); }; const addMessageHandler = resolve => { const messageHandler = ({origin, data:{from}, data:{id}, data:{results}}) => { if (origin == document.location.origin && from == 'TaskArchive' && id == messageId) { let projectedEarnings = 0; for (let {monetary_reward} of results) { projectedEarnings += monetary_reward; } resolve('$' + (projectedEarnings / 100).toFixed(2)); } }; disconnect = projectedEarnings => { window.removeEventListener('message', messageHandler); GM_setValue(today(), projectedEarnings); return projectedEarnings; }; window.addEventListener('message', messageHandler); }; return new Promise(resolve => { addMessageHandler(resolve); setTimeout(resolve, 1E3, 'error'); queryEarnings(); }).then(disconnect); }; for (let property in elementStyle) { element.style[property] = elementStyle[property]; } element.textContent = await GM_getValue(today(), '$0.00'); document.body.appendChild(element); window.postMessage({ destination: 'TaskArchive', startEvents: { stateChange: ['pending', 'rejected'] }}, document.location.origin); window.addEventListener('message', async ({origin, data:{from}, data:{event}, data:{type}, data:{data}}) => { if (origin == document.location.origin && from == 'TaskArchive' && event == 'stateChange' && (type == 'pending' || type == 'rejected') && data[0].date == today()) { element.textContent = await update(); } }); })();