Upwork: Hide jobs with hires

Hide the jobs where someone has already been hired

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name        Upwork: Hide jobs with hires
// @namespace   https://www.stardecimal.com/
// @version     1
// @description Hide the jobs where someone has already been hired
// @author      lifeweaver
// @grant       none
// @include     https://www.upwork.com/ab/jobs/search/*
// ==/UserScript==

/* jshint esversion: 6 */

(function (_undefined) {
  
	// ===================================================================
	// Tried of clicking on the jobs with hires already?
  //
	// Script style and some functions from YouTube: Hide Watched Videos - https://github.com/EvHaus/youtube-hide-watched

	// ====================================================================

	// Enable for debugging
	const __DEV__ = false;

	const logDebug = (msg) => {
		// eslint-disable-next-line no-console
		if (__DEV__) console.log(msg);
	};

	// ===========================================================

	const debounce = function (func, wait, immediate) {
		let timeout;
		return (...args) => {
			const later = () => {
				timeout = null;
				if (!immediate) func.apply(this, args);
			};
			const callNow = immediate && !timeout;
			clearTimeout(timeout);
			timeout = setTimeout(later, wait);
			if (callNow) func.apply(this, args);
		};
	};
  
  // ===========================================================
  
  // There is probably some normal way to get these, but I don't know how so...
  const getCookie = function (name) {
      var value = '';
      document.cookie.split(';').forEach(function(item, index) {
          if(item.includes(name)) {
              value = item.split('=').pop()
          }
      });
      return value;
  }
  
  // ===========================================================

  // Called after getting the details for each job
  const reqListener = function () {
      var jobDetails = JSON.parse(this.responseText);
      logDebug('[UW-JHH] totalHired: ', jobDetails.job.clientActivity.totalHired);
      if(jobDetails.job.clientActivity.totalHired > 0) {
          //Drop the first one
          var responseUrlArray = this.responseURL.split('/');
          responseUrlArray.pop()

          //JobId is the second to last
          var jobId = responseUrlArray.pop();

          document.querySelector('a[href*="' + jobId + '"]').closest('section').remove();
      }
  }

  // ===========================================================
  
  const lookForJobs = function () {
    document.querySelectorAll('.job-title-link').forEach(function(item, index) {
        var jobId = item.href.split('_').pop();
        jobId = jobId.slice(0, jobId.length -1);
        var detailsUrl = "https://www.upwork.com/job-details/jobdetails/api/job/" + jobId + "/summary";

        var xhr = new XMLHttpRequest();
        xhr.addEventListener("load", reqListener);
        xhr.open("GET", detailsUrl);
        xhr.setRequestHeader('Authorization', "Bearer " + getCookie('oauth2_global_js_token'));
        xhr.setRequestHeader('X-Odesk-Csrf-Token', getCookie('XSRF-TOKEN'));
        xhr.setRequestHeader('x-odesk-user-agent', 'oDesk LM');
        xhr.setRequestHeader('x-requested-with', 'XMLHttpRequest');
        xhr.send();
    });
  }
  
	const run = debounce((mutations) => {
		logDebug('[UW-JHH] Running check for jobs with hires');
		lookForJobs();
	}, 250);

	// ===========================================================
  
	const observeDOM = (function () {
		const MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
		const eventListenerSupported = window.addEventListener;

		return function (obj, callback) {
			logDebug('[UW-JHH] Attaching DOM listener');

			// Invalid `obj` given
			if (!obj) return;

			if (MutationObserver) {
				const obs = new MutationObserver(((mutations, _observer) => {
					if (mutations[0].addedNodes.length || mutations[0].removedNodes.length) {
						// eslint-disable-next-line callback-return
						callback(mutations);
					}
				}));

				obs.observe(obj, {childList: true, subtree: true});
			} else if (eventListenerSupported) {
				obj.addEventListener('DOMNodeInserted', callback, false);
				obj.addEventListener('DOMNodeRemoved', callback, false);
			}
		};
	}());

  
	logDebug('[UW-JHH] Starting Script');
  
	// Listen for ANY DOM change event, and re-run the script.
	observeDOM(document.body, run);
  
  // Initial run
  run();
  
}());