Greasy Fork is available in English.

[Worker] Today's Projected Earnings (mTurk)

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();
    }
  });
})();