Upwork: Hide jobs with hires

Hide the jobs where someone has already been hired

当前为 2021-09-06 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴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();
  
}());