Files
greasemonkey_scripts/ebay_core.js
2025-05-27 23:54:20 -04:00

191 lines
9.1 KiB
JavaScript

// ebay_core.js - Shared Parsing & Extraction Logic
(function (root, factory) {
if (typeof module === 'object' && module.exports) {
// Node.js. Does not work with strict CommonJS, but
// works in a Node environment for use with fs.readFileSync + injection.
module.exports = factory();
} else {
// Browser globals (Greasemonkey via @require)
root.EbayParser = factory();
}
}(typeof self !== 'undefined' ? self : this, function () {
'use strict';
const EbayParser = {}; // The object we will export/attach
EbayParser.parseSizeAndQuantity = function(title) {
title = title ? title.toUpperCase() : "";
let totalTB = 0;
let quantity = 1;
let needed_description_check = false;
let individualSizeTB = 0;
const explicitQtyPatterns = [
/\b(?:LOT\s+OF|LOT)\s*\(?\s*(\d+)\s*\)?/i,
/\b(?:LOT\s+OF|LOT)\s*\*\s*(\d+)/i,
/\b(?:PACK\s+OF|PACK|BULK)\s*\(?\s*(\d+)\s*\)?/i,
/\b(\d+)\s*-\s*PACK\b/i,
/\b(\d+)\s*COUNT\b/i
];
for (const pattern of explicitQtyPatterns) {
const qtyMatch = title.match(pattern);
if (qtyMatch && qtyMatch[1]) {
const parsedQty = parseInt(qtyMatch[1], 10);
if (parsedQty > 0 && parsedQty < 500) {
quantity = parsedQty;
break;
}
}
}
const sizeMatches = [];
const sizeRegex = /(\d+(?:\.\d+)?)\s*(TB|GB)(?:\b|(?=\s|-|,|\(|\)|$))/g;
let match;
while ((match = sizeRegex.exec(title)) !== null) {
sizeMatches.push({ value: parseFloat(match[1]), unit: match[2].toUpperCase() });
}
if (sizeMatches.length > 0) {
const uniqueSizesTB = [...new Set(
sizeMatches.map(sm => sm.unit === 'GB' ? sm.value / 1000 : sm.value)
)].sort((a, b) => a - b);
if (uniqueSizesTB.length > 0) {
individualSizeTB = uniqueSizesTB[0];
if (uniqueSizesTB.length > 1) needed_description_check = true;
}
}
if (title.match(/\d+(?:\.\d+)?\s*(?:GB|TB)\s*(?:-|&|OR|TO)\s*\d+(?:\.\d+)?\s*(?:GB|TB)/i)) {
needed_description_check = true;
}
if (quantity > 1 && title.includes("MIXED")) {
needed_description_check = true;
}
if (title.includes("CHECK THE DESCRIPTION") || title.includes("CHECK DESCRIPTION") || title.includes("SEE DESCRIPTION")) {
if (quantity > 1 || sizeMatches.length === 0 || sizeMatches.length > 1) {
needed_description_check = true;
}
}
if (individualSizeTB > 0) {
totalTB = individualSizeTB * quantity;
}
if (quantity > 1 && totalTB === 0) {
needed_description_check = true;
}
if (quantity === 1 && sizeMatches.length === 1 && !needed_description_check) {
needed_description_check = false;
}
return { totalTB: parseFloat(totalTB.toFixed(4)), quantity, needed_description_check };
};
EbayParser.parsePrice = function(priceText) {
priceText = priceText || "";
if (priceText.toLowerCase().includes(' to ')) {
return null;
}
const priceMatch = priceText.match(/\$?([\d,]+\.?\d*)/);
if (priceMatch) {
return parseFloat(priceMatch[1].replace(/,/g, ''));
}
return null;
};
EbayParser.runUnitTests = function() {
// Ensure console exists (for Node vs Browser safety, though Node has it)
const log = typeof console !== 'undefined' ? console.log : function() {};
const error = typeof console !== 'undefined' ? console.error : function() {};
log("Ebay Cost/TB: --- Running Unit Tests ---");
const testCases = [
{ title: "LOT OF (9) MAJOR BRAND 2.5\" 7MM SSD * Kingston, Samsung, SanDisk& PNY*120-250GB", expected: { totalTB: 1.080, quantity: 9, needed_description_check: true } },
{ title: "Lot of 10 Intel 256 GB 2.5\" SATA SSD different Model check the Description", expected: { totalTB: 2.560, quantity: 10, needed_description_check: true } },
{ title: "Lot of*10 Mixed brands 240GB-256GB 2.5\" SATA SSD Drives Working & tested", expected: { totalTB: 2.400, quantity: 10, needed_description_check: true } },
{ title: "Lot of 9 SSD 120&128 GB 2.5\" SATA different brands check the description", expected: { totalTB: 1.080, quantity: 9, needed_description_check: true } },
{ title: "Bulk 5 Lot Samsung 870 EVO 500GB SSD SATA - Used - Tested Passed Smart Test", expected: { totalTB: 2.500, quantity: 5, needed_description_check: false } },
{ title: "Samsung 1.6TB NVME PCIe 3.0 x8 2.75\" SSD MZPLK1T6HCHP PM1725 Series TLC", expected: { totalTB: 1.6, quantity: 1, needed_description_check: false } },
{ title: "Brand New Crucial X6 2TB Portable External SSD (CT2000X6SSD9)", expected: { totalTB: 2.0, quantity: 1, needed_description_check: false } },
{ title: "Western Digital WD_BLACK SN850X 2TB NVMe Internal SSD", expected: { totalTB: 2.0, quantity: 1, needed_description_check: false } },
{ title: "Corsair Force Series MP600 1TB Gen4 PCIe X4 NVMe M.2 SSD Up to 4950 MB/s CSSD...", expected: { totalTB: 1.0, quantity: 1, needed_description_check: false } },
{ title: "Micron 5100 MAX 1.84TB SATA 6Gb/s 2.5\" SSD MTFDDAK1T9TCC-1AR1ZABYY", expected: { totalTB: 1.84, quantity: 1, needed_description_check: false } },
{ title: "Dell 0HGX92 1.6TB 2.5” PCIe NVMe Gen4 SSD Intel D7-P5600 SSDPF2KE016T9T HGX92 ES", expected: { totalTB: 1.6, quantity: 1, needed_description_check: false } },
{ title: "10-PACK 1TB SSD", expected: { totalTB: 10.0, quantity: 10, needed_description_check: false } },
{ title: "LOT OF 2X 1TB SSDs", expected: { totalTB: 2.0, quantity: 2, needed_description_check: false } }
];
let testsPassed = 0;
let testsFailed = 0;
testCases.forEach((test, index) => {
const result = EbayParser.parseSizeAndQuantity(test.title);
const totalTBCheck = Math.abs(result.totalTB - test.expected.totalTB) < 0.0001;
const quantityCheck = result.quantity === test.expected.quantity;
const neededCheck = result.needed_description_check === test.expected.needed_description_check;
if (totalTBCheck && quantityCheck && neededCheck) {
testsPassed++;
} else {
error(`Test ${index + 1}: FAILED - "${test.title}"`);
error(` Expected: totalTB=${test.expected.totalTB.toFixed(4)}, Q=${test.expected.quantity}, Check=${test.expected.needed_description_check}`);
error(` Actual: totalTB=${result.totalTB.toFixed(4)}, Q=${result.quantity}, Check=${result.needed_description_check}`);
testsFailed++;
}
});
log(`--- Unit Test Summary: ${testsPassed} Passed, ${testsFailed} Failed ---`);
return testsFailed === 0;
};
// This function is INTENDED TO RUN IN THE BROWSER via Puppeteer
EbayParser.extractDataFromPage = function() {
const itemSelector = 'li.s-item, li.srp-results__item, div.s-item[role="listitem"]';
const itemElements = document.querySelectorAll(itemSelector);
const items = [];
const today = new Date().toISOString();
itemElements.forEach(item => {
const titleElement = item.querySelector('.s-item__title, .srp-results__title');
const priceElement = item.querySelector('.s-item__price, .srp-results__price');
const linkElement = item.querySelector('.s-item__link, a[href*="/itm/"]');
const title = titleElement ? titleElement.innerText.trim() : null;
const priceText = priceElement ? priceElement.innerText.trim() : null;
const itemUrl = linkElement ? linkElement.href : null;
if (!title || !priceText || !itemUrl) return;
// Use the parser functions (assuming 'EbayParser' is global/available)
const listingPrice = EbayParser.parsePrice(priceText);
const parsedInfo = EbayParser.parseSizeAndQuantity(title);
const totalTB = parsedInfo.totalTB;
const needed_description_check = parsedInfo.needed_description_check;
let costPerTB = null;
if (listingPrice !== null && totalTB > 0) {
costPerTB = listingPrice / totalTB;
}
let itemId = null;
const itemMatch = itemUrl.match(/\/itm\/(\d+)/);
if (itemMatch && itemMatch[1]) {
itemId = itemMatch[1];
}
items.push({
title,
itemId,
dateFound: today,
listingPrice,
totalTB: totalTB > 0 ? parseFloat(totalTB.toFixed(3)) : null,
costPerTB: costPerTB !== null ? parseFloat(costPerTB.toFixed(2)) : null,
needed_description_check,
itemUrl
});
});
return items;
};
return EbayParser; // Return the object
}));