Skip to content

Instantly share code, notes, and snippets.

@barakplasma
Last active March 20, 2024 18:30
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save barakplasma/a391ca5fb0738922d2a330f5ea03ff76 to your computer and use it in GitHub Desktop.
Save barakplasma/a391ca5fb0738922d2a330f5ea03ff76 to your computer and use it in GitHub Desktop.
Display if KSP items in category are available nearby (on context menu right click)
// ==UserScript==
// @name Show in stock on KSP
// @namespace http://tampermonkey.net/
// @version 0.1
// @description try to take over the world!
// @author You
// @match https://ksp.co.il/web/cat/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=co.il
// @grant GM.xmlHttpRequest
// @connect ksp.co.il
// @run-at context-menu
// @downloadURL https://gist.github.com/barakplasma/a391ca5fb0738922d2a330f5ea03ff76/raw
// @updateURL https://gist.github.com/barakplasma/a391ca5fb0738922d2a330f5ea03ff76/raw
// ==/UserScript==
(function () {
'use strict';
console.debug('on ksp category page')
const catalogNumbers = getItems();
console.debug(catalogNumbers);
catalogNumbers.forEach(catnum => {
checkAvailability(catnum)
});
})();
function checkAvailability(catnum) {
const url = `https://ksp.co.il/m_action/api/mlay/${catnum}`;
// @ts-ignore
const { xmlHttpRequest } = GM;
xmlHttpRequest({
method: "GET",
url: url,
headers: {
"Content-Type": "application/json"
},
onreadystatechange: function (response) {
console.debug('ready state change', response.readyState)
if (response.readyState === 4) {
const json = JSON.parse(response.responseText);
console.debug('response', json)
displayAvailability(catnum, json)
}
},
onerror: function (response) {
console.error('error', response)
},
ontimeout: function (response) {
console.error('timeout', response)
}
});
}
/**
*
* @param {Availability} json
*/
function isAvailable(json) {
const { hashmonaim, ksptelaviv, dizingof } = json?.result?.stores;
console.debug('hashmonaim', hashmonaim)
console.debug('ksptelaviv', ksptelaviv)
const availability = hashmonaim.qnt > 1 || ksptelaviv.qnt >= 1 || dizingof.qnt >= 1;
return availability;
}
const selector = 'div[aria-label^=מספר]'
/**
*
* @param {string | number} catnum
* @param {Availability} json
*/
function displayAvailability(catnum, json) {
const availability = isAvailable(json);
if (availability) {
console.debug('available', catnum)
const catnumdiv = document.querySelector(`div[aria-label="catalog number${catnum}"] > span`);
if (catnumdiv) {
// @ts-ignore
catnumdiv.style.color = 'green';
} else {
console.warn('could not find catnum div', catnum)
}
}
}
function getItems() {
const selector = '[data-id^=product]';
const catalogDivs = [...document.querySelectorAll(selector)]
const catalogNumbers = catalogDivs.map(el => {
const catnum = el.getAttribute('aria-label')?.replace('catalog number', '')
if (typeof catnum === 'string') {
return parseInt(catnum)
} else {
console.warn('could not parse catalog number', catnum)
return catnum
}
});
return catalogNumbers;
}
/**
* GM_xmlhttpRequest allows a userscripts to send an HTTP request and handle the response.
* @typedef {function} GM_xmlHttpRequest
* @param {Object} details - An object containing the details of the request to be sent and the callback functions to be called when the response is received.
* @param {('GET'|'HEAD'|'POST')} details.method - The HTTP method to use.
* @param {string} details.url - The destination URL.
* @param {Object} details.headers - Headers to be sent with the request.
* @param {string} details.data - Some string to send via a POST request.
* @param {('follow'|'error'|'manual')} details.redirect - Controls what happens when a redirect is detected.
* @param {string} details.cookie - A cookie to be patched into the sent cookie set.
* @param {boolean} details.binary - Send the data string in binary mode.
* @param {boolean} details.nocache - Don't cache the resource.
* @param {boolean} details.revalidate - Revalidate maybe cached content.
* @param {number} details.timeout - A timeout in ms.
* @param {*} details.context - A property which will be added to the response object.
* @param {('arraybuffer'|'blob'|'json'|'stream')} details.responseType - The responseType.
* @param {string} details.overrideMimeType - A MIME type for the request.
* @param {boolean} details.anonymous - Don't send cookies with the request.
* @param {boolean} details.fetch - Use a fetch instead of a XMLHttpRequest request.
* @param {string} details.user - A user name for authentication.
* @param {string} details.password - A password.
* @param {function} details.onabort - Callback to be executed if the request was aborted.
* @param {function} details.onerror - Callback to be executed if the request ended up with an error.
* @param {function} details.onloadstart - Callback to be executed on load start.
* @param {function} details.onprogress - Callback to be executed if the request made some progress.
* @param {function} details.onreadystatechange - Callback to be executed if the request's readyState changed.
* @param {function} details.ontimeout - Callback to be executed if the request failed due to a timeout.
* @param {function} details.onload - Callback to be executed if the request was loaded.
*/
/**
* @typedef {Object} GMResponse
* @property {string} finalUrl - The final URL after all redirects from where the data was loaded.
* @property {number} readyState - The request's readyState.
* @property {number} status - The request's status.
* @property {string} statusText - The request's status text.
* @property {string} responseHeaders - The request's response headers.
* @property {*} response - The response data as object if details.responseType was set.
* @property {Document} responseXML - The response data as XML document.
* @property {string} responseText - The response data as plain string.
*
* @callback onload
* @param {Response} response - The response from the request.
*/
/**interface Result {
stores: { [key: string]: Store };
shipment: number;
}
interface Store {
id: string;
name: string;
qnt: number;
}
**/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment