Last active
January 9, 2019 00:48
-
-
Save cuylerstuwe/a0547ed21ee51fabaccb270b7655b232 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // ==UserScript== | |
| // @name mTurk Title Bar Timer / Wage | |
| // @author Cuyler Stuwe (salembeats) | |
| // @namespace salembeats | |
| // @version 54 | |
| // @description Title bar timer/counter. Latest updates: Dynamic favicon. Minor refactors, including removal of old WWW site code. Minor potential performance improvement from caching element selector calls in order to speed things up with minimal code structure changes. | |
| // @include https://worker.mturk.com/projects/* | |
| // @icon https://i.imgur.com/Y68Qxdd.png | |
| // @grant GM_setValue | |
| // @grant GM_getValue | |
| // ==/UserScript== | |
| const base64IconHeader = `data:image/x-icon;base64,`; | |
| const base64PngHeader = `data:image/png;base64,`; | |
| const base64ErrorIcon = `${base64PngHeader}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`; | |
| const base64WorkIcon = `${base64PngHeader}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`; | |
| function changeFaviconTo(url) { | |
| const faviconElement = document.querySelector("[rel='shortcut icon']") || document.createElement("link"); | |
| faviconElement.rel = 'shortcut icon'; | |
| faviconElement.href = url; | |
| document.head.appendChild(faviconElement); | |
| } | |
| const ALWAYS_TICK_WAGE_TIMER = true; | |
| const SHOW_BIG_EMOJI = true; | |
| const BIG_EMOJI_SIZE = "250px"; | |
| const BIG_EMOJI_OPACITY_ZERO_TO_ONE = "0.03"; | |
| const ONE_SECOND_IN_MS = 1000; | |
| const LOVE_WAGE_LOWER_LIMIT = 30.00; | |
| const HAPPY_WAGE_LOWER_LIMIT = 20.00; | |
| const OK_WAGE_LOWER_LIMIT = 10.00; | |
| const SAD_WAGE_LOWER_LIMIT = 5.00; | |
| const DISGUSTED_WAGE_LOWER_LIMIT = 0.00; | |
| const LOVE_WAGE_EMOJI = "😍"; | |
| const HAPPY_WAGE_EMOJI = "😀"; | |
| const OK_WAGE_EMOJI = "😐"; | |
| const SAD_WAGE_EMOJI = "😭"; | |
| const DISGUSTED_WAGE_EMOJI = "💩"; | |
| const wageLimitToEmoji = { | |
| [LOVE_WAGE_LOWER_LIMIT]: LOVE_WAGE_EMOJI, | |
| [HAPPY_WAGE_LOWER_LIMIT]: HAPPY_WAGE_EMOJI, | |
| [OK_WAGE_LOWER_LIMIT]: OK_WAGE_EMOJI, | |
| [SAD_WAGE_LOWER_LIMIT]: SAD_WAGE_EMOJI, | |
| [DISGUSTED_WAGE_LOWER_LIMIT]: DISGUSTED_WAGE_EMOJI | |
| }; | |
| const wageEmojiToSpanSelector = { | |
| [HAPPY_WAGE_EMOJI]: "#happyWageSpan", | |
| [OK_WAGE_EMOJI]: "#okWageSpan", | |
| [SAD_WAGE_EMOJI]: "#sadWageSpan", | |
| [DISGUSTED_WAGE_EMOJI]: "#disgustedWageSpan", | |
| [LOVE_WAGE_EMOJI]: "#loveWageSpan" | |
| }; | |
| const UPDATE_RATE_IN_MILLISECONDS = (ALWAYS_TICK_WAGE_TIMER ? (ONE_SECOND_IN_MS / 2) : ONE_SECOND_IN_MS); | |
| const selectorCache = { | |
| }; | |
| function selectFromCache(selector) { | |
| const cachedResult = selectorCache[selector]; | |
| if(cachedResult) { return cachedResult; } | |
| else { | |
| const element = document.querySelector(selector); | |
| selectorCache[selector] = element; | |
| return element; | |
| } | |
| } | |
| var Utility = (function createUtility() { | |
| const _scriptStartTime = new Date().getTime(); | |
| const _fallbackHitStartTime = (unsafeWindow.pageTimes === undefined ? _scriptStartTime : unsafeWindow.pageTimes.beginPageLoad); | |
| const _HITStartTime = (performance.timing === undefined ? _fallbackHitStartTime : performance.timing.navigationStart); | |
| const _HITLoadTime =_scriptStartTime - _HITStartTime; | |
| let _HITLoadTimeAccuracy; | |
| if(performance.timing === undefined) { | |
| if(unsafeWindow.pageTimes === undefined) { | |
| _HITLoadTimeAccuracy = "low"; | |
| } | |
| else { | |
| _HITLoadTimeAccuracy = "medium"; | |
| } | |
| } | |
| else { | |
| _HITLoadTimeAccuracy = "high"; | |
| } | |
| let _allContentLoadedTime; | |
| let _allContentLoadedCallback = () => {}; | |
| document.addEventListener('readystatechange', function(event) { | |
| if(document.readyState === "complete") { | |
| _allContentLoadedTime = performance.now(); | |
| _allContentLoadedCallback(); | |
| } | |
| }); | |
| var _secondsVisible = 0; | |
| var _pauseOnInvisible = true; | |
| function getHITStartTime() { | |
| return _HITStartTime; | |
| } | |
| function getHITLoadTime() { | |
| return _HITLoadTime; | |
| } | |
| function getAllContentLoadedTime() { | |
| return _allContentLoadedTime; | |
| } | |
| function setAllContentLoadedCallback(newFn) { | |
| _allContentLoadedCallback = newFn; | |
| } | |
| function getHITLoadTimeAccuracy() { | |
| return _HITLoadTimeAccuracy; | |
| } | |
| function getSecondsSinceStartTime() { | |
| return ( new Date().getTime() - _HITStartTime) / 1000; | |
| } | |
| function isWindowTopFrame() { | |
| return (window === window.top); | |
| } | |
| function updateSecondsVisible() { | |
| if(!document.hidden && document.hasFocus()) {incrementSecondsVisible();} | |
| } | |
| function incrementSecondsVisible() { | |
| _secondsVisible += (UPDATE_RATE_IN_MILLISECONDS / ONE_SECOND_IN_MS); | |
| } | |
| function getSecondsVisible() { | |
| return _secondsVisible; | |
| } | |
| function hourlyWageDollars(secondsPassed, rewardCents) { | |
| return (rewardCents / secondsPassed) * 36; | |
| } | |
| function hmsToSeconds(hours, minutes, seconds) { | |
| return hoursToSeconds(hours) + minutesToSeconds(minutes) + seconds; | |
| } | |
| function minutesToSeconds(minutes) { | |
| return (minutes * 60); | |
| } | |
| function toMMSSString(secondsRemaining) { | |
| let minutesRemaining = Math.floor(secondsRemaining/60); | |
| let remainderSeconds = secondsRemaining - (minutesRemaining * 60); | |
| const localeOptions = {useGrouping: false, minimumIntegerDigits: 2, maximumFractionDigits: 0}; | |
| return minutesRemaining.toLocaleString(undefined,localeOptions) + ":" + remainderSeconds.toLocaleString(undefined,localeOptions); | |
| } | |
| function daysToSeconds(days) { | |
| return (days * 86400); | |
| } | |
| function hoursToSeconds(hours) { | |
| return (hours * 3600); | |
| } | |
| function secondsRemainingInHHMMSSCountdown(hhmmssString) { | |
| let values = hhmmssString.split(":"); | |
| return hmsToSeconds(Number(values[0]), Number(values[1]), Number(values[2])); | |
| } | |
| function secondsRemainingInMMSSCountdown(mmssString) { | |
| let values = mmssString.split(":"); | |
| let minutes = Number(values[0]); | |
| let seconds = Number(values[1]); | |
| return minutesToSeconds(minutes) + seconds; | |
| } | |
| function secondsRemainingInMMSSCountup(mmssString, totalSeconds) { | |
| let countupValues = mmssString.split(":"); | |
| let countupMinutes = Number(countupValues[0]); | |
| let countupSeconds = Number(countupValues[1]); | |
| let totalSecondsCounted = (countupMinutes * 60) + countupSeconds; | |
| return totalSeconds - totalSecondsCounted; | |
| } | |
| function secondsRemainingInHHMMSSCountup(hhmmssString, totalSeconds) { | |
| let values = hhmmssString.split(":"); | |
| return totalSeconds - hmsToSeconds(Number(values[0]), Number(values[1]), Number(values[2])); | |
| } | |
| function secondsGoalForTargetWage(desiredCentsPerHour, jobCents) { | |
| let desiredCentsPerSecond = desiredCentsPerHour / 3600; | |
| return jobCents / desiredCentsPerSecond; | |
| } | |
| function secondsPassed(totalSeconds, secondsRemaining) { | |
| return totalSeconds - secondsRemaining; | |
| } | |
| function dollarsToCents(dollars) { | |
| return dollars * 100; | |
| } | |
| function askWorkerFrameWhetherSurvey() { | |
| selectFromCache("iframe").contentWindow.postMessage({msg: "Are you a survey HIT?"}, "*"); | |
| } | |
| function disablePauseOnInvisible() { | |
| _pauseOnInvisible = false; | |
| } | |
| function isPausingOnInvisible() { | |
| return _pauseOnInvisible; | |
| } | |
| function highlightWageRange(cssSelectorString) { | |
| selectFromCache(cssSelectorString).style = "font-weight: bold; text-decoration: underline;"; | |
| } | |
| function unhighlightWageRange(cssSelectorString) { | |
| selectFromCache(cssSelectorString).style = "font-weight: normal; text-decoration: none;"; | |
| } | |
| function highlightOnlyWageRange(cssSelectorString) { | |
| Utility.highlightWageRange(cssSelectorString); | |
| ["#happyWageSpan", | |
| "#okWageSpan", | |
| "#sadWageSpan", | |
| "#disgustedWageSpan", | |
| "#loveWageSpan"].filter(selector => selector !== cssSelectorString).forEach(selector => { | |
| Utility.unhighlightWageRange(selector); | |
| }); | |
| } | |
| return { | |
| getSecondsSinceStartTime, | |
| getHITStartTime, | |
| isWindowTopFrame, | |
| updateSecondsVisible, | |
| getSecondsVisible, | |
| hourlyWageDollars, | |
| minutesToSeconds, | |
| toMMSSString, | |
| secondsRemainingInMMSSCountdown, | |
| secondsRemainingInMMSSCountup, | |
| secondsPassed, | |
| dollarsToCents, | |
| askWorkerFrameWhetherSurvey, | |
| disablePauseOnInvisible, | |
| isPausingOnInvisible, | |
| hmsToSeconds, | |
| secondsRemainingInHHMMSSCountdown, | |
| secondsRemainingInHHMMSSCountup, | |
| daysToSeconds, | |
| secondsGoalForTargetWage, | |
| highlightWageRange, | |
| unhighlightWageRange, | |
| highlightOnlyWageRange, | |
| getHITLoadTime, | |
| getHITLoadTimeAccuracy, | |
| getAllContentLoadedTime, | |
| setAllContentLoadedCallback | |
| }; | |
| })(); | |
| function markHitAsExpired(requesterName) { | |
| document.title = `EXPIRED - ${requesterName}`; | |
| changeFaviconTo(base64ErrorIcon); | |
| } | |
| function updateBigEmoji(whichEmoji) { | |
| if(SHOW_BIG_EMOJI) { selectFromCache("#pageEmoji").innerText = whichEmoji; } | |
| } | |
| function getEmojiAndUpdateBigEmoji(hourlyWageDollars) { | |
| let returnedEmoji = ""; | |
| [LOVE_WAGE_LOWER_LIMIT, | |
| HAPPY_WAGE_LOWER_LIMIT, | |
| OK_WAGE_LOWER_LIMIT, | |
| SAD_WAGE_LOWER_LIMIT, | |
| DISGUSTED_WAGE_LOWER_LIMIT].find(limit => { | |
| const emoji = wageLimitToEmoji[limit]; | |
| const spanSelector = wageEmojiToSpanSelector[emoji]; | |
| if(hourlyWageDollars > limit) { | |
| updateBigEmoji(emoji); | |
| Utility.highlightOnlyWageRange(spanSelector); | |
| returnedEmoji = emoji; | |
| return true; | |
| } | |
| else { | |
| return false; | |
| } | |
| }); | |
| return returnedEmoji; | |
| } | |
| function getPausedStringIfPaused() { | |
| if( !ALWAYS_TICK_WAGE_TIMER && ( !(document.visible && document.hasFocus()) ) ) { | |
| return `(\$ timer paused)`; | |
| } | |
| else { | |
| return ""; | |
| } | |
| } | |
| function updatePageLoadTimeSpan() { | |
| const pageLoadSpan = selectFromCache("#timeLostToPageLoad"); | |
| if(pageLoadSpan.innerText.trim() === "") { | |
| pageLoadSpan.innerText = Utility.getHITLoadTime().toFixed(0); | |
| } | |
| } | |
| function updateFullPageLoadTimeSpan() { | |
| const fullPageLoadSpan = selectFromCache("#timeLostToFullPageLoad"); | |
| if(fullPageLoadSpan.innerText.trim() === "") { | |
| if(Utility.getAllContentLoadedTime()) { | |
| fullPageLoadSpan.innerText = Utility.getAllContentLoadedTime().toFixed(0); | |
| } | |
| } | |
| } | |
| function getSecondsPassedCount() { | |
| if(Utility.isPausingOnInvisible() && (!ALWAYS_TICK_WAGE_TIMER)) { | |
| return Utility.getSecondsVisible(); | |
| } | |
| else { | |
| return Utility.getSecondsSinceStartTime(); | |
| } | |
| } | |
| function updateActiveHITTabTimer(requesterName, secondsRemaining, rewardInCents) { | |
| if( secondsRemaining <= 0 ){ | |
| markHitAsExpired(requesterName); | |
| return; | |
| } | |
| Utility.updateSecondsVisible(); | |
| updatePageLoadTimeSpan(); | |
| updateFullPageLoadTimeSpan(); | |
| const secondsPassed = getSecondsPassedCount(); | |
| const hourlyWageDollars = Utility.hourlyWageDollars(secondsPassed, rewardInCents + ( selectFromCache("#bonusWageCents").value !== "" ? | |
| Utility.dollarsToCents(selectFromCache("#bonusWageCents").value) : | |
| 0 | |
| ) | |
| ); | |
| selectFromCache("#timeWorkedSpan").innerText = Utility.toMMSSString(secondsPassed); | |
| document.title = `${Utility.toMMSSString(secondsRemaining)} ${getEmojiAndUpdateBigEmoji(hourlyWageDollars)} \$${hourlyWageDollars.toFixed(2)}/hr. ${requesterName} ${getPausedStringIfPaused()}`; | |
| } | |
| function collapseTimerBar() { | |
| selectFromCache("#titleBarTimerBar").style.left = "-100%"; | |
| selectFromCache("#expanderBar").style.left = "50%"; | |
| GM_setValue("timerBarVisible", false); | |
| } | |
| function expandTimerBar() { | |
| selectFromCache("#titleBarTimerBar").style.left = "50%"; | |
| selectFromCache("#expanderBar").style.left = "-100%"; | |
| GM_setValue("timerBarVisible", true); | |
| } | |
| function restoreTimerBarCollapseState() { | |
| let isTimerBarVisible = GM_getValue("timerBarVisible"); | |
| if(isTimerBarVisible !== undefined) { | |
| if(!isTimerBarVisible) { | |
| collapseTimerBar(); | |
| } | |
| } | |
| } | |
| function getSecondsForWageTargets(rewardInCents) { | |
| const secondsForLoveWage = Utility.secondsGoalForTargetWage(Utility.dollarsToCents(LOVE_WAGE_LOWER_LIMIT), rewardInCents); | |
| const secondsForHappyWage = Utility.secondsGoalForTargetWage(Utility.dollarsToCents(HAPPY_WAGE_LOWER_LIMIT), rewardInCents); | |
| const secondsForOKWage = Utility.secondsGoalForTargetWage(Utility.dollarsToCents(OK_WAGE_LOWER_LIMIT), rewardInCents); | |
| const secondsForSadWage = Utility.secondsGoalForTargetWage(Utility.dollarsToCents(SAD_WAGE_LOWER_LIMIT), rewardInCents); | |
| const secondsForDisgustedWage = Utility.secondsGoalForTargetWage(Utility.dollarsToCents(DISGUSTED_WAGE_LOWER_LIMIT), rewardInCents); | |
| return { | |
| love: secondsForLoveWage, | |
| happy: secondsForHappyWage, | |
| ok: secondsForOKWage, | |
| sad: secondsForSadWage, | |
| disgusted: secondsForDisgustedWage | |
| }; | |
| } | |
| function insertTimerBar(wageTargets) { | |
| document.body.insertAdjacentHTML('afterend', | |
| `<div id='titleBarTimerBar' style="position: fixed !important; pointer-events: none !important; background: white !important; opacity: 0.95 !important; width: 100% !important; left: 50% !important; margin-left: -50% !important; top: 0px !important; z-index: ${Number.MAX_SAFE_INTEGER} !important; text-align: center !important;">` + | |
| `<span id="loveWageSpan">${LOVE_WAGE_EMOJI}: (<= ${Utility.toMMSSString(wageTargets.love)})</span> ` + | |
| `<span id="happyWageSpan">${HAPPY_WAGE_EMOJI}: (${Utility.toMMSSString(wageTargets.love)} - ${Utility.toMMSSString(wageTargets.happy)})</span> ` + | |
| `<span id="okWageSpan">${OK_WAGE_EMOJI}: (${Utility.toMMSSString(wageTargets.happy)} - ${Utility.toMMSSString(wageTargets.ok)})</span> ` + | |
| `<span id="sadWageSpan">${SAD_WAGE_EMOJI}: (${Utility.toMMSSString(wageTargets.ok)} - ${Utility.toMMSSString(wageTargets.sad)})</span> ` + | |
| `<span id="disgustedWageSpan">${DISGUSTED_WAGE_EMOJI}: (>= ${Utility.toMMSSString(wageTargets.sad)})</span>` + | |
| `<div style="text-align: center !important; margin-left: auto !important; margin-right: auto !important; font-style: italic !important;">Time Worked: <span id="timeWorkedSpan">00:00</span> <input type="text" id="bonusWageCents" style="pointer-events: auto !important;" placeholder="Bonus $" size="5"> <div>Pageload: <span id="timeLostToPageLoad"></span>ms Complete: <span id="timeLostToFullPageLoad"></span>ms</div></div>` + | |
| `<button id='hideBarButton' style="pointer-events: auto !important;">Hide</button>` + | |
| '</div>' | |
| ); | |
| } | |
| function insertExpanderBar() { | |
| document.body.insertAdjacentHTML('afterend', | |
| `<div id='expanderBar' style="position: fixed; pointer-events: none; background: white; opacity: 0.95; width: 100%; left: -100%; margin-left: -50%; top: 0px; z-index: ${Number.MAX_SAFE_INTEGER}; text-align: center;">` + | |
| `<button id='showBarButton' style="pointer-events: auto;">Show $/hr. Details</button>` + | |
| '</div>' | |
| ); | |
| } | |
| function setUpSurveyHintingCommunications() { | |
| window.addEventListener("message", function handleMessage(event) { | |
| if(event.data.msg === "I'm ready for you to ask me questions.") { | |
| Utility.askWorkerFrameWhetherSurvey(); | |
| } | |
| else if(event.data.msg === "I am a survey HIT.") { | |
| Utility.disablePauseOnInvisible(); | |
| } | |
| }); | |
| } | |
| function acceptedHitInit() { | |
| } | |
| function elementExists(element) { | |
| return element !== undefined && element instanceof Element; | |
| } | |
| function main() { | |
| if(!Utility.isWindowTopFrame()) { | |
| return; | |
| } | |
| const hitModalProps = selectFromCache(`[data-react-class*="require('reactComponents/common/ShowModal')"]`).getAttribute("data-react-props"); | |
| const modalPropsJson = JSON.parse(hitModalProps); | |
| const requesterName = modalPropsJson.modalOptions.requesterName; | |
| const rewardInDollars = modalPropsJson.modalOptions.monetaryReward.amountInDollars; | |
| const rewardInCents = Utility.dollarsToCents(rewardInDollars); | |
| const notAcceptedSpan = selectFromCache(`span[data-react-props*='"text":"accept"']`); | |
| if(elementExists(notAcceptedSpan)) { | |
| document.title = `NOT ACCEPTED - ${requesterName}`; | |
| changeFaviconTo(base64ErrorIcon); | |
| return; | |
| } | |
| changeFaviconTo(base64WorkIcon); | |
| setUpSurveyHintingCommunications(); | |
| const countdownTimer = selectFromCache("span[data-react-class*='reactComponents/common/CompletionTimer'] span:last-of-type"); | |
| const minutesOfTimeGiven = (countdownTimer.innerText.trim().match(/(\d+) Min/)||[0,0])[1]; | |
| const secondsOfTimeGiven = 0; | |
| const maximumTimeGivenInSeconds = Utility.hmsToSeconds(0, minutesOfTimeGiven, secondsOfTimeGiven); | |
| const wageTargetsSeconds = getSecondsForWageTargets(rewardInCents); | |
| insertTimerBar(wageTargetsSeconds); | |
| insertExpanderBar(); | |
| selectFromCache('#hideBarButton').addEventListener('click', function hideBar() { | |
| collapseTimerBar(); | |
| }); | |
| selectFromCache('#showBarButton').addEventListener('click', function hideBar() { | |
| expandTimerBar(); | |
| }); | |
| restoreTimerBarCollapseState(); | |
| if(SHOW_BIG_EMOJI) { | |
| document.body.insertAdjacentHTML('afterend', | |
| `<div id="pageEmoji" draggable="false" style="position: fixed; opacity: ${BIG_EMOJI_OPACITY_ZERO_TO_ONE}; font-size: ${BIG_EMOJI_SIZE}; pointer-events: none; user-drag: none; user-select: none; width: 100%; left: 0px; height: 50%; top: 50%; z-index: ${Number.MAX_SAFE_INTEGER}; text-align: center;">` + | |
| `` + | |
| `</div>`); | |
| } | |
| setInterval(function workerSiteUpdate() { | |
| const countdownTimerText = countdownTimer.innerText.match(/\d+:\d+\b/)[0]; | |
| const secondsRemaining = Utility.secondsRemainingInMMSSCountup(countdownTimerText, maximumTimeGivenInSeconds); | |
| updateActiveHITTabTimer(requesterName, secondsRemaining, rewardInCents); | |
| }, UPDATE_RATE_IN_MILLISECONDS); | |
| } | |
| main(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment