JavaScript Ninja - Crowd Wisdom eBay Enhancements

Posted at

Making eBay Buying Safer, Using Wisdom Of The Crowd.


Protect Yourself Against:
- Untrustworthy sellers
Those will accept your money but will not send you anything.
- Bad-reputation sellers
without checking out their feedbacks.
- New and inexperienced sellers
without researching their profile.




- Only trust sellers with "a lot of buyers".
- Avoid items with overpriced shipping.
- Sort by "number of sold items" - in additional to current sorted results.




Script #1 - remove unsold items
javascript:(function(items){Array.prototype.forEach.call(items,function(e){if(-1!==e.innerText.indexOf(" sold"))return;e.style.cssText="display:none;";e.setAttribute("ignoreme","")});return true}(document.querySelectorAll('li[id^="item"]')));





Script #2 - remove overpriced-shipping items
javascript:(function(items,max_shipping){Array.prototype.forEach.call(items,function(e){e.match_result=e.innerText.match(/ (\\d+\\.*\\d*) shipping/im);if(null===e.match_result)return;if(undefined===typeof e.match_result[1])return;e.match_result=Number(e.match_result[1]);if(e.match_result<max_shipping)return;e.style.cssText="display:none;";e.setAttribute("ignoreme","")});return true})(document.querySelectorAll('li[id^="item"]'),Number(prompt("Max Shipping","30")));





Script #3 - sort by most-sold items
javascript:(function(items){NodeList.prototype.map=Array.prototype.map;items=items.map(function(e){return e}).sort(function(a,b){a=Number(a.innerHTML.match(/(\\d+).* sold/)[1]);b=Number(b.innerHTML.match(/(\\d+).* sold/)[1]);return a-b});items=items.reverse();items=items.map(function(e){return e.cloneNode(true)});(function(placeholder){placeholder.style.cssText="display:none;";placeholder.innerHTML="";items.forEach(function(item){placeholder.appendChild(item)});placeholder.style.cssText=""})(document.querySelector("ul#ListViewInner"));return true}(document.querySelectorAll('li[id^="item"]:not([ignoreme])')));







Developer Hub [April 16th]

The following code will remove items that were never sold.
javascript:(function(items){
NodeList.prototype.forEach = Array.prototype.forEach;

items.forEach(function(e){
if(-1 !== e.innerText.indexOf(" sold")) return;

e.style.display = "none";

setTimeout(function(){
e.parentNode.removeChild(e);
},10);
});
return true;
}(
document.querySelectorAll('li[id^="item"]')
));


bookmarklet version:
javascript:(function(items){NodeList.prototype.forEach=Array.prototype.forEach;items.forEach(function(e){if(-1!==e.innerText.indexOf(" sold"))return;e.style.display="none";setTimeout(function(){e.parentNode.removeChild(e)},10)});return true})(document.querySelectorAll('li[id^="item"]'));






- Display items sorted by "most sold" to "least sold".
- better keep page showing few items.
- works great combined with other built-in eBay sorting (such as by price) for best result keep page showing fewer results.

if you've runned the code before, then, you are having only the sellers that has "x sold" on their item, however it is still hard to see which one is the best, in that case the one-seller that sold the most of this item,

running the following code will rearrange the item list listing from "most sold" to "least sold".

javascript:(function(items){
NodeList.prototype.map = Array.prototype.map;

/* natural sort (few - many) */
items = items.map(function(e){ return e; }).sort(function(a,b){
a = Number(a.innerHTML.match(/(\\d+).* sold/)[1]);
b = Number(b.innerHTML.match(/(\\d+).* sold/)[1]);
return a - b;
});

/* many - few */
items = items.reverse();

items = items.map(function(e){ return e.cloneNode(true); });

(function(placeholder){
placeholder.innerHTML = "";
placeholder.style.cssText = "display:none;";

items.forEach(function(item){
placeholder.appendChild(item);
});

placeholder.style.cssText = "";
}(
document.querySelector('ul#ListViewInner')
));

return true;
}(
document.querySelectorAll('li[id^="item"]')
));


bookmarklet version:
javascript:(function(items){NodeList.prototype.map=Array.prototype.map;items=items.map(function(e){return e}).sort(function(a,b){a=Number(a.innerHTML.match(/(\\d+).* sold/)[1]);b=Number(b.innerHTML.match(/(\\d+).* sold/)[1]);return a-b});items=items.reverse();items=items.map(function(e){return e.cloneNode(true)});(function(placeholder){placeholder.innerHTML="";placeholder.style.cssText="display:none;";items.forEach(function(item){placeholder.appendChild(item)});placeholder.style.cssText=""})(document.querySelector("ul#ListViewInner"));return true})(document.querySelectorAll('li[id^="item"]'));






Developer Hub [April 19th]

Speeding stuff up:
- less DOM manipulation, faster processing.
- query take-into account ignored nodes (whom were previously removed).

javascript: (function (items) {
Array.prototype.forEach.call(items, function (e) {
if (-1 !== e.innerText.indexOf(" sold")) return;

e.style.cssText = "display:none;";
e.setAttribute("ignoreme","");
});
return true;
}(
document.querySelectorAll('li[id^="item"]')
));

/* ----- */

javascript: (function (items) {
NodeList.prototype.map = Array.prototype.map;

items = items.map(function (e) {return e}).sort(function (a, b) {
a = Number(a.innerHTML.match(/(\\d+).* sold/)[1]);
b = Number(b.innerHTML.match(/(\\d+).* sold/)[1]);
return a - b
});
items = items.reverse();
items = items.map(function (e) {return e.cloneNode(true)});

(function (placeholder) {
placeholder.style.cssText = "display:none;";
placeholder.innerHTML = "";
items.forEach(function (item) {
placeholder.appendChild(item)
});
placeholder.style.cssText = ""
})(document.querySelector("ul#ListViewInner"));

return true
}(
document.querySelectorAll('li[id^="item"]:not([ignoreme])')
));




bookmarklets:
javascript:(function(items){Array.prototype.forEach.call(items,function(e){if(-1!==e.innerText.indexOf(" sold"))return;e.style.cssText="display:none;";e.setAttribute("ignoreme","")});return true})(document.querySelectorAll('li[id^="item"]'));






Developer Hub [April 24th]

overpriced-shipping removal
Shipping from USA or UK to Israel (for example) has really overpriced shipping fee,
but only sometimes...
So instead of filtering it from the search, you might want to run this code,
effectively removing items with overpriced shipping-fee from the search,

later, you can run any sort of codes like the "sort by most sold" which will ignored the removed items :)

javascript: (function (items) {
Array.prototype.forEach.call(items, function (e) {
e.match_result = e.innerText.match(/ (\\d+\\.*\\d*) shipping/im);

if(null === e.match_result) return
if(undefined === typeof e.match_result[1]) return

e.match_result = Number( e.match_result[1] );

if(e.match_result < 30.0) return;

e.style.cssText = "display:none;";
e.setAttribute("ignoreme", "")

});
return true
}(document.querySelectorAll('li[id^="item"]')));


naturally you can modify to 30 value to higher/lower value...



Developer Hub [April 24th #2]

custom max-shipping:
javascript: (function (items, max_shipping) {
Array.prototype.forEach.call(items, function (e) {
e.match_result = e.innerText.match(/ (\\d+\\.*\\d*) shipping/im);
if (null === e.match_result) return;
if (undefined === typeof e.match_result[1]) return;
e.match_result = Number(e.match_result[1]);
if (e.match_result < max_shipping) return;
e.style.cssText = "display:none;";
e.setAttribute("ignoreme", "")
});
return true
})(
document.querySelectorAll('li[id^="item"]')
, Number(prompt("Max Shipping", "30"))
);






edit: June 17, 2016
remove ebay sellers with low rating:

(function(elements, minimal_value, regex, element_rating_value){
NodeList.prototype.forEach = Array.prototype.forEach;

elements.forEach(function(element){
element_rating_value = element.innerText.match(regex);
element_rating_value = (null === element_rating_value || "undefined" === element_rating_value[1]) ? Number.MIN_SAFE_INTEGER : element_rating_value[1];

if(element_rating_value > minimal_value) return;

element.setAttribute("ignoreme", "")
element.style.cssText = "display:none;" ;
});
}(
document.querySelectorAll('li[id^="item"]')
,
(function(DEFAULT_VALUE, result){
result = prompt("Max Shipping", String(DEFAULT_VALUE) );
result = Number(result);
result = 0 === result || "nan" === String(result).toLowerCase() ? DEFAULT_VALUE : result;
return result;
}(
98.5
, null
))

, /Seller\\:\\ [^\\%]+ (\\d+\\.*\\d*)\\%/im
, null
));




bookmarklet format:

javascript:(function(elements,minimal_value,regex,element_rating_value){NodeList.prototype.forEach=Array.prototype.forEach;elements.forEach(function(element){element_rating_value=element.innerText.match(regex);element_rating_value=null===element_rating_value||"undefined"===element_rating_value[1]?Number.MIN_SAFE_INTEGER:element_rating_value[1];if(element_rating_value>minimal_value)return;element.setAttribute("ignoreme","");element.style.cssText="display:none;"})})(document.querySelectorAll('li[id^="item"]'),function(DEFAULT_VALUE,result){result=prompt("Max Shipping",String(DEFAULT_VALUE));result=Number(result);result=0===result||"nan"===String(result).toLowerCase()?DEFAULT_VALUE:result;return result}(98.5,null),/Seller\\:\\ [^\\%]+ (\\d+\\.*\\d*)\\%/im,null);







Edit: August The 2nd, 2016: Better Overprice Shipping Filter.

This one uses a bit of logic to handle the "shipping not specified" (handles the item as "bad" or "overpriced") and specifically handles "free international shipping" (handles the item as "good")

javascript: (function (items, max_shipping) {
Array.prototype.forEach.call(items, function (e) {
/* end cases */
if (e.innerText.toLowerCase()
.indexOf("free international shipping")) return; /*Good*/

if (e.innerText.toLowerCase()
.indexOf("shipping not specified")) { /*bad*/
e.style.cssText = "display:none;";
e.setAttribute("ignoreme", "");
return;
}

/* real cases */

e.match_result = e.innerText.match(/ (\\d+\\.*\\d*) shipping/im); /* extract */

/* error cases */
if (null === e.match_result || "undefined" === typeof e.match_result[1]) { /*bad case: unknown form of shipping-price..*/
e.style.cssText = "display:none;";
e.setAttribute("ignoreme", "");
return;
}

e.match_result = Number(e.match_result.shift()); /* normalize */

if (0 === e.match_result) { /*bad case by logic: prices are never "0" so something is wrong..*/
e.style.cssText = "display:none;";
e.setAttribute("ignoreme", "");
return;
}

/*compare*/
if (e.match_result >= max_shipping) { /*bad case: overpriced shipping.*/
e.style.cssText = "display:none;";
e.setAttribute("ignoreme", "");
}

/*good*/
/* at this point the item is left unmodified, meaning the shipping is suitable for the input rate. */
});
return true
})(document.querySelectorAll('li[id^="item"]'), Number(prompt("Max Shipping", "30")));


and here is the minified-bookmarklet version:
javascript:(function(a,b){return Array.prototype.forEach.call(a,function(a){return a.innerText.toLowerCase().indexOf("free international shipping")?void 0:a.innerText.toLowerCase().indexOf("shipping not specified")?(a.style.cssText="display:none;",void a.setAttribute("ignoreme","")):(a.match_result=a.innerText.match(/ (\\d+\\.*\\d*) shipping/im),null===a.match_result||"undefined"==typeof a.match_result[1]?(a.style.cssText="display:none;",void a.setAttribute("ignoreme","")):(a.match_result=Number(a.match_result.shift()),0===a.match_result?(a.style.cssText="display:none;",void a.setAttribute("ignoreme","")):void(a.match_result>=b&&(a.style.cssText="display:none;",a.setAttribute("ignoreme","")))))}),!0}(document.querySelectorAll('li[id^="item"]'),Number(prompt("Max Shipping","30"))));




and finally,
the following code will fetch the items from the next page,
and add them to the current page, once it is done you can run it
again, and again and again...
if you are viewing the lists at maximum capacity, each time you'll add 200 items to the list,
this way you can run the codes above on much more items at a time (just keep in mind that the browser might hang a little-bit)


(function(get){ "use strict";
var current_page_pagination_button = document.querySelector('.pages a[aria-label*="Selected"]')
,next_page_pagination_button = document.querySelector('.pages a[aria-label*="Selected"] + a[aria-label*="Pagination"]')
;

if(null === current_page_pagination_button || null === next_page_pagination_button){
console.log("SOFT ERROR: could not find current or next page buttons.");
return false;
}

console.log("trying to get: [" + next_page_pagination_button.href + "]");

get(next_page_pagination_button.href, function(response, response_headers, response_url){
console.log("get done", response, response_headers, response_url);

var current_list = document.querySelector("div#ResultSetItems ul#ListViewInner")
,next_page_items = response.querySelector('div#ResultSetItems ul#ListViewInner')
;
console.log(current_list, next_page_items);

//"cure" lazy-loading images.
next_page_items.querySelectorAll('img[src*="ebaystatic"][src*=".gif"][imgurl]').forEach(function(img){
img.setAttribute("src", img.getAttribute("imgurl").replace(/http\\:/i, "https:"));
img.removeAttribute("imgurl");
img.removeAttribute("onload");
});
//prevent any script tags..
next_page_items.querySelectorAll('script').forEach(function(script){
script.removeAttribute("src");
script.innerHTML = "";
});

console.log("adding list from: [" + next_page_pagination_button.href + "]");
current_list.innerHTML += next_page_items.innerHTML; //next page item into this page-list.


//on success update the current status in the pagination buttons so this code may be run again (copy&&paste) and fetch the next-next page :]
current_page_pagination_button.setAttribute("aria-label", current_page_pagination_button.getAttribute("aria-label").replace(/Selected/g, ""));
next_page_pagination_button.setAttribute("aria-label", next_page_pagination_button.getAttribute("aria-label") + " Selected"); //really.. just add the word "Selected" somewhere...
//this will also update the blue square style around current page
current_page_pagination_button.classList.remove("curr");
next_page_pagination_button.classList.add("curr");
//add more style
current_page_pagination_button.style.cssText = "background:none limegreen;";
});

}(
function get(url, callback){
var xhr;

function readystatechange_handler(ev){
console.log("readystatechange_handler", xhr);

var response, responseURL;
if(XMLHttpRequest.DONE !== xhr.readyState) return; //not completed yet

console.log("done", xhr);

//xhr.removeEventListener("readystatechange", readystatechange_handler, {capture:false, passive:true}); //ready (cleanup)
if(200 !== xhr.status && 302 !== xhr.status){ //failed (cleanup) return false will stop the event.
console.log("SOFT ERROR: request status is not 200/302", xhr.status, xhr);
return false;
}

console.log("ok", xhr.status);

setTimeout(function(){
callback.apply(undefined,[xhr.response, xhr.getAllResponseHeaders(), xhr.responseURL]);
}, 20);
console.log("ebay successs");
return false; //will stop the event.
}

xhr = new XMLHttpRequest();
xhr.addEventListener("readystatechange", readystatechange_handler, {capture:false, passive:true});
xhr.open('GET', url, true);
xhr.setRequestHeader("X-Hello", "World!");
xhr.responseType = "document";
xhr.timeout = 3000;
//xhr.withCredentials = true;
xhr.overrideMimeType("text/html;charset=UTF-8;lang=en-US;language=English");
xhr.send();
}
));





The script here:
iCompile - JavaScript Snippet – eBay – Fetch Accurate "Sold" Amount And Update The Main Page will get you an accurate amount sold (if any, ..or zero..) for each item on the list. This way you can ignore the "remove unsold items" script (above), and simply run the "sort by sold amount" script (above.. too..)