eBay Seller Location Fork

Displays the registration location of eBay sellers on search results and product pages.

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

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

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

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

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         eBay Seller Location Fork
// @namespace    http://tampermonkey.net/
// @version      1.2.2
// @description  Displays the registration location of eBay sellers on search results and product pages.
// @icon         https://raw.githubusercontent.com/sonofevil/eBaySellerLocationFork/main/ebaysellerlocationicon64.png
// @author       sonofevil, master131
// @license      MIT
// @match        https://www.ebay.*.*/sch/*
// @match        https://www.ebay.*/sch/*
// @match        https://www.ebay.*.*/itm/*
// @match        https://www.ebay.*/itm/*
// @require      http://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js
// @grant        GM_xmlhttpRequest
// @run-at       document-end
// @noframes
// ==/UserScript==

(async function() {
  'use strict';

  //HTTP request headers
  const reqhead = {
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    'X-Requested-With': 'XMLHttpRequest',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/118.0',
    'Cookie': document.cookie,
    'Sec-Fetch-Dest': 'document',
    'Sec-Fetch-Mode': 'navigate',
    'Sec-Fetch-Site':	'same-origin',
    'Sec-Fetch-User':	'?1',
    'TE':	'trailers',
    'Upgrade-Insecure-Requests': 1
  }

  // Inline styling for counter
  const counterStyle = "position: fixed; bottom: 10px; right: 10px; border-width: 1px; border-color: black; border-style: solid; padding: 5px; background-color: white"

  // DOM element selectors. First thing to debug when the script stops working.
  const selSrchRes = {
    entry: 'ul.srp-results > li.s-item div.s-item__info',
    link: 'a.s-item__link',
    info: 'span.s-item__seller-info,span.s-item__etrs',
    name: 'span.s-item__seller-info-text,span.s-item__etrs-text'
  }
  const selItmPage = {
    loc: '[class$="nameAndAddress"] [class$="content"] [class$="item"]:last-child',
    usrlnk: '.d-stores-info-categories__container__info__section__title a.ux-action[href]',
    info: 'div.ux-seller-section, div.x-sellercard-atf__info',
  }
  const selSlrPage_loc = 'section.str-about-description__seller-info > span:first-of-type > span.str-text-span.BOLD';

  //Inserts location info element into page
  function insertLocInfo(target, location) {
    //var data = JSON.parse(JSON.parse(info.responseText));
    if (target) {
      console.log("Inserting seller location...");
      var loc = document.createElement("div");
      loc.innerText = 'Location: ' + location.replace("HongKong", "Hong Kong");
      target.insertAdjacentElement('afterend', loc);
    }
  }

  // Creates counter container and returns counter span
  function createCounter() {
      var container = document.createElement("div");
      document.querySelector('html > body').insertAdjacentElement('afterend', container);
      const title = document.createTextNode("Seller locations:");
      container.appendChild(title);
      const br = document.createElement("br");
      container.appendChild(br);
      const counter = document.createElement("span");
      container.appendChild(counter);
      container.setAttribute ("style", counterStyle);
      return counter;
  }

  // Return document from URL (.URL attribute is wrong, but the DOM content is right)
  async function getUrlDocument(url) {
    return await fetch(url, { headers: reqhead })
      .then(response => response.text())
      .then(html => {
        var parser  = new DOMParser ();
        var redoc   = parser.parseFromString(html, "text/html");
        return redoc;
    })
      .catch(error => {
      throw new Error("Error: Failure to fetch page.");
    });
  }

  // Return location string for item doc
  async function getDocLoc(itemDoc) {
    if (await itemDoc !== undefined) {
      // Seek location on /itm/ page
      var locElem = await itemDoc.querySelector(selItmPage.loc);
      if (await locElem !== null) {
        console.log("Location found on item page.")
        // Return location string if found on /itm/ page
        return locElem.innerText;
      } else {
        console.log("Location not found on item page, checking seller info page...")
        // Get seller's user link
        var slrLnk = await itemDoc.querySelector(selItmPage.usrlnk);
        if (await slrLnk !== null) {
          console.log("Seller info URL: " + slrLnk.href + '&_tab=about')
          // Get doc from user info URL
          var infoDoc = await getUrlDocument(slrLnk.href + '&_tab=about');
          console.log(infoDoc);
          // Return location string
          if (await infoDoc !== null) {
            return await infoDoc.querySelector(selSlrPage_loc).innerText;
          } else {
            throw new Error("Failure in loading page.");
          }
        } else {
          throw new Error("Couldn't find location.")
        }
      }
    } else {
      throw new Error("Couldn't find location.")
    }
  }

  // Get doc from /itm/ URL
  async function getUrlLoc(itmUrl) {
    var doc = await getUrlDocument(itmUrl);
    return getDocLoc(doc);
  }

  async function searchResults () {
    //Saves all item links to array
    const srcResults = await document.querySelectorAll(selSrchRes.entry);
    const resNum = await srcResults.length;
    const nameList = [];
    const locaList = [];
    var counter = createCounter();
    var errCount = 0;
    counter.innerText = "0/" + resNum  + "(Err: 0)";
    var i = 0;
    for (const [index, result] of srcResults.entries()) {
      if (result) {
        try{
          let name = result.querySelector(selSrchRes.name).innerText.split(" ")[0];
          let nameIndex = nameList.indexOf(name);
          let sellInfo = result.querySelector(selSrchRes.info);
          if ( nameIndex <= 0 ) {
            nameList[i] = name;
            let itemLink = result.querySelector(selSrchRes.link);
            console.log("Checking search result for seller location: " + itemLink.href)
            let itmDoc = await getUrlDocument(itemLink.href);
            locaList[i] = await getDocLoc(itmDoc);
            console.log("Inserting location " + locaList[i])
            await insertLocInfo(sellInfo, locaList[i]);
            i++;
          } else {
            console.log("Item's seller " + name + " already known. Inserting location " + locaList[nameIndex]);
            await insertLocInfo(sellInfo, locaList[nameIndex]);
          }
        } catch(e) {
          console.log(e);
          errCount++;
        }
        counter.innerText = ( index + 1 ) + "/" + resNum + " (Err: " + errCount + ")";
      }
    }
  }

  //Search results:
  if (document.URL.includes("/sch/")) {
    searchResults();
  //Item pages
  } else if (document.URL.includes("/itm/")) {
    //Selects element with username
    var infoSection = document.querySelector(selItmPage.info);
    insertLocInfo(infoSection, await getDocLoc(document));
  }

})();