kopia lustrzana https://github.com/dgtlmoon/changedetection.io
Restock detection - Check all elements for text to get stock status from, only consider elements inside the viewport, only consider elements more than 100px from the top (avoid menu) , trim any text returned (#2040)
rodzic
65428655b8
commit
1749c07750
|
@ -61,4 +61,4 @@ class perform_site_check(difference_detection_processor):
|
||||||
# Always record the new checksum
|
# Always record the new checksum
|
||||||
update_obj["previous_md5"] = fetched_md5
|
update_obj["previous_md5"] = fetched_md5
|
||||||
|
|
||||||
return changed_detected, update_obj, self.fetcher.instock_data.encode('utf-8')
|
return changed_detected, update_obj, self.fetcher.instock_data.encode('utf-8').strip()
|
||||||
|
|
|
@ -48,12 +48,22 @@ function isItemInStock() {
|
||||||
'tijdelijk uitverkocht',
|
'tijdelijk uitverkocht',
|
||||||
'unavailable tickets',
|
'unavailable tickets',
|
||||||
'we do not currently have an estimate of when this product will be back in stock.',
|
'we do not currently have an estimate of when this product will be back in stock.',
|
||||||
|
'we don\'t know when or if this item will be back in stock.',
|
||||||
'zur zeit nicht an lager',
|
'zur zeit nicht an lager',
|
||||||
'品切れ',
|
'品切れ',
|
||||||
'已售完',
|
'已售完',
|
||||||
'품절'
|
'품절'
|
||||||
];
|
];
|
||||||
|
|
||||||
|
function getElementBaseText(element) {
|
||||||
|
// .textContent can include text from children which may give the wrong results
|
||||||
|
// scan only immediate TEXT_NODEs, which will be a child of the element
|
||||||
|
var text = "";
|
||||||
|
for (var i = 0; i < element.childNodes.length; ++i)
|
||||||
|
if (element.childNodes[i].nodeType === Node.TEXT_NODE)
|
||||||
|
text += element.childNodes[i].textContent;
|
||||||
|
return text.toLowerCase().trim();
|
||||||
|
}
|
||||||
|
|
||||||
const negateOutOfStockRegexs = [
|
const negateOutOfStockRegexs = [
|
||||||
'[0-9] in stock'
|
'[0-9] in stock'
|
||||||
|
@ -63,18 +73,22 @@ function isItemInStock() {
|
||||||
negateOutOfStockRegexs_r.push(new RegExp(negateOutOfStockRegexs[0], 'g'));
|
negateOutOfStockRegexs_r.push(new RegExp(negateOutOfStockRegexs[0], 'g'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The out-of-stock or in-stock-text is generally always above-the-fold
|
||||||
|
// and often below-the-fold is a list of related products that may or may not contain trigger text
|
||||||
|
// so it's good to filter to just the 'above the fold' elements
|
||||||
|
// and it should be atleast 100px from the top to ignore items in the toolbar, sometimes menu items like "Coming soon" exist
|
||||||
|
const elementsToScan = Array.from(document.getElementsByTagName('*')).filter(element => element.getBoundingClientRect().top + window.scrollY <= window.innerHeight && element.getBoundingClientRect().top + window.scrollY >= 100);
|
||||||
|
|
||||||
const elementsWithZeroChildren = Array.from(document.getElementsByTagName('*')).filter(element => element.children.length === 0);
|
var elementText = "";
|
||||||
|
|
||||||
// REGEXS THAT REALLY MEAN IT'S IN STOCK
|
// REGEXS THAT REALLY MEAN IT'S IN STOCK
|
||||||
for (let i = elementsWithZeroChildren.length - 1; i >= 0; i--) {
|
for (let i = elementsToScan.length - 1; i >= 0; i--) {
|
||||||
const element = elementsWithZeroChildren[i];
|
const element = elementsToScan[i];
|
||||||
if (element.offsetWidth > 0 || element.offsetHeight > 0 || element.getClientRects().length > 0) {
|
elementText = "";
|
||||||
var elementText="";
|
|
||||||
if (element.tagName.toLowerCase() === "input") {
|
if (element.tagName.toLowerCase() === "input") {
|
||||||
elementText = element.value.toLowerCase();
|
elementText = element.value.toLowerCase();
|
||||||
} else {
|
} else {
|
||||||
elementText = element.textContent.toLowerCase();
|
elementText = getElementBaseText(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (elementText.length) {
|
if (elementText.length) {
|
||||||
|
@ -86,24 +100,23 @@ function isItemInStock() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// OTHER STUFF THAT COULD BE THAT IT'S OUT OF STOCK
|
// OTHER STUFF THAT COULD BE THAT IT'S OUT OF STOCK
|
||||||
for (let i = elementsWithZeroChildren.length - 1; i >= 0; i--) {
|
for (let i = elementsToScan.length - 1; i >= 0; i--) {
|
||||||
const element = elementsWithZeroChildren[i];
|
const element = elementsToScan[i];
|
||||||
if (element.offsetWidth > 0 || element.offsetHeight > 0 || element.getClientRects().length > 0) {
|
if (element.offsetWidth > 0 || element.offsetHeight > 0 || element.getClientRects().length > 0) {
|
||||||
var elementText="";
|
elementText = "";
|
||||||
if (element.tagName.toLowerCase() === "input") {
|
if (element.tagName.toLowerCase() === "input") {
|
||||||
elementText = element.value.toLowerCase();
|
elementText = element.value.toLowerCase();
|
||||||
} else {
|
} else {
|
||||||
elementText = element.textContent.toLowerCase();
|
elementText = getElementBaseText(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (elementText.length) {
|
if (elementText.length) {
|
||||||
// and these mean its out of stock
|
// and these mean its out of stock
|
||||||
for (const outOfStockText of outOfStockTexts) {
|
for (const outOfStockText of outOfStockTexts) {
|
||||||
if (elementText.includes(outOfStockText)) {
|
if (elementText.includes(outOfStockText)) {
|
||||||
return elementText; // item is out of stock
|
return outOfStockText; // item is out of stock
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -114,4 +127,5 @@ function isItemInStock() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns the element text that makes it think it's out of stock
|
// returns the element text that makes it think it's out of stock
|
||||||
return isItemInStock();
|
return isItemInStock().trim()
|
||||||
|
|
||||||
|
|
Ładowanie…
Reference in New Issue