Amazon Suchergebnis Verbesserer

Verbessern Sie Amazon-Suchergebnisse durch Hinzufügen von Nummern, Werbe-IDs und Best Sellers Rank.

  1. // ==UserScript==
  2. // @name Amazon Search Result Enhancer
  3. // @name:zh 亚马逊搜索结果添加序号和广告ID
  4. // @name:de Amazon Suchergebnis Verbesserer
  5. // @name:ja Amazon 検索結果エンハンサー
  6. // @name:fr Amazon Amélioration des résultats de recherche
  7. // @name:it Amazon Miglioratore di risultati di ricerca
  8. // @name:nl Amazon Zoekresultaten Verbeteraar
  9. // @name:es Amazon Mejorador de Resultados de Búsqueda
  10. // @namespace https://noobbei.top
  11. // @version 1.6.0
  12. // @description Enhance Amazon search results by adding numbers, advertisement IDs, and Best Sellers Rank.
  13. // @description:de Verbessern Sie Amazon-Suchergebnisse durch Hinzufügen von Nummern, Werbe-IDs und Best Sellers Rank.
  14. // @description:ja 広告ID、番号、そしてベストセラーランクを追加してAmazon検索結果を向上させます。
  15. // @description:fr Améliorez les résultats de recherche Amazon en ajoutant des numéros, des identifiants de publicité et des classements de meilleures ventes.
  16. // @description:it Migliora i risultati di ricerca di Amazon aggiungendo numeri, ID pubblicitari e Best Sellers Rank.
  17. // @description:nl Verbeter Amazon zoekresultaten door nummers, advertentie-ID's en Best Sellers Rank toe te voegen.
  18. // @description:es Mejora los resultados de búsqueda de Amazon añadiendo números, ID de anuncios y Best Sellers Rank.
  19. // @description:zh 为亚马逊搜索结果页面上的广告和自然搜索结果添加序号,并为广告结果添加广告ID和活动ID,同时显示Best Sellers Rank。
  20. // @author noobbei
  21. // @match https://www.amazon.com/*
  22. // @match https://www.amazon.co.uk/*
  23. // @match https://www.amazon.de/*
  24. // @match https://www.amazon.it/*
  25. // @match https://www.amazon.fr/*
  26. // @match https://www.amazon.es/*
  27. // @match https://www.amazon.se/*
  28. // @match https://www.amazon.com.mx/*
  29. // @match https://www.amazon.co.jp/*
  30. // @match https://www.amazon.ca/*
  31. // @icon https://www.amazon.com/favicon.ico
  32. // @license MIT
  33. // @grant none
  34. // ==/UserScript==
  35.  
  36. (function () {
  37. 'use strict';
  38.  
  39. const translations = {
  40. 'zh': {'AdID': '广告ID', 'CampaignID': '活动ID', 'BestSellersRank': '畅销榜排名'},
  41. 'en': {'AdID': 'Ad ID', 'CampaignID': 'Campaign ID', 'BestSellersRank': 'Best Sellers Rank'},
  42. 'de': {'AdID': 'Werbe-ID', 'CampaignID': 'Kampagnen-ID', 'BestSellersRank': 'Verkaufsrang'},
  43. 'fr': {'AdID': 'ID Publicité', 'CampaignID': 'ID Campagne', 'BestSellersRank': 'Classement Meilleures Ventes'},
  44. 'es': {'AdID': 'ID Anuncio', 'CampaignID': 'ID Campaña', 'BestSellersRank': 'Clasificación de Ventas'},
  45. 'it': {'AdID': 'ID Annuncio', 'CampaignID': 'ID Campagna', 'BestSellersRank': 'Classifica Bestseller'},
  46. 'nl': {'AdID': 'Advertentie-ID', 'CampaignID': 'Campagne-ID', 'BestSellersRank': 'Verkooprang'},
  47. 'ca': {'AdID': 'ID Anunci', 'CampaignID': 'ID Campanya', 'BestSellersRank': 'Classificació de Vendes'},
  48. 'ko': {'AdID': '광고ID', 'CampaignID': '캠페인ID', 'BestSellersRank': '베스트셀러 순위'},
  49. 'ja': {'AdID': '広告ID', 'CampaignID': 'キャンペーンID', 'BestSellersRank': 'ベストセラーランキング'}
  50. };
  51.  
  52. // 动态检测用户的浏览器或网站语言
  53. let lang = navigator.language || navigator.userLanguage;
  54. lang = lang.split('-')[0]; // 处理类似'en-US'的语言代码
  55.  
  56. let adID_k = translations[lang].AdID;
  57. let campaignID_k = translations[lang].CampaignID;
  58. let bestSellersRank_k = translations[lang].BestSellersRank;
  59.  
  60. const applyLabelsAndIds = () => {
  61. // 计数器重置
  62. let adCounter = 1;
  63. let searchResultCounter = 1;
  64.  
  65. // 获取所有搜索结果的元素
  66. let searchResults = document.querySelectorAll('div[data-component-type="s-search-result"], .sbv-video-single-product');
  67.  
  68. // 清除之前的序号和ID标签
  69. document.querySelectorAll('.ad-counter-label, .search-result-counter-label').forEach(label => {
  70. label.remove();
  71. });
  72. document.querySelectorAll('.ad-id-element, .campaign-id-element, .best-sellers-rank-element').forEach(idElem => {
  73. idElem.remove();
  74. });
  75.  
  76. searchResults.forEach(result => {
  77. let label;
  78. let adIdElement;
  79. let campaignIdElement;
  80. let bestSellersRankElement;
  81.  
  82. // 检查是否已添加过标签
  83. if (result.querySelector('.ad-counter-label, .search-result-counter-label')) {
  84. return; // 如果已添加标签,跳过这个元素
  85. }
  86.  
  87. // 检查是否是广告
  88. if (result.classList.contains('AdHolder') || result.classList.contains('sbv-video-single-product')) {
  89. // 创建序号标签
  90. label = createLabel(`${adCounter}`, 'gold', '#000');
  91. label.classList.add('ad-counter-label'); // 添加自定义类以避免重复添加
  92.  
  93. // 从data-s-safe-ajax-modal-trigger属性获取广告ID
  94. let adDataAttribute = result.querySelector('[data-s-safe-ajax-modal-trigger]');
  95. let adId = null;
  96. let campaignId = null;
  97. if (adDataAttribute) {
  98. const adData = JSON.parse(adDataAttribute.getAttribute('data-s-safe-ajax-modal-trigger'));
  99. let ajaxUrl = adData.ajaxUrl;
  100. adId = decodeURIComponent(ajaxUrl).match(/"adId":"([^"]*)"/)[1];
  101. campaignId = decodeURIComponent(ajaxUrl).match(/"campaignId":"([^"]*)"/)[1];
  102. }
  103.  
  104. // 如果找到广告ID,则创建并添加一个包含广告ID的标签
  105. if (adId) {
  106. adIdElement = createIdElement(`${adID_k}: ${adId}`, 'ad-id-element');
  107. }
  108.  
  109. if (campaignId) {
  110. campaignIdElement = createIdElement(`${campaignID_k}: ${campaignId}`, 'campaign-id-element');
  111. }
  112.  
  113. // 增加广告计数器
  114. adCounter++;
  115.  
  116. } else {
  117. // 创建序号标签
  118. label = createLabel(`${searchResultCounter}`, 'green', '#FFF');
  119. label.classList.add('search-result-counter-label'); // 添加自定义类以避免重复添加
  120.  
  121. // 增加搜索结果计数器
  122. searchResultCounter++;
  123. }
  124.  
  125. // 获取并创建 Best Sellers Rank 标签
  126. let rankElement = result.querySelector('span.a-size-small.a-text-normal');
  127. if (rankElement) {
  128. let rankText = rankElement.textContent.trim();
  129. if (rankText) {
  130. bestSellersRankElement = createIdElement(`${bestSellersRank_k}: ${rankText}`, 'best-sellers-rank-element');
  131. }
  132. }
  133.  
  134. // 将序号标签预置到搜索结果元素的标题下方
  135. const titleElement = result.querySelector('div[data-cy="title-recipe"]'); // 标题元素的选择器可能依网页而异
  136. if (titleElement) {
  137. let infoContainer = createInfoContainer();
  138. infoContainer.appendChild(label); // 序号标签
  139. if (adIdElement) {
  140. let adIdContainer = document.createElement('span');
  141. adIdContainer.appendChild(adIdElement);
  142. infoContainer.appendChild(adIdContainer);
  143. }
  144.  
  145. if (campaignIdElement) {
  146. let campaignIdContainer = document.createElement('div');
  147. campaignIdContainer.appendChild(campaignIdElement);
  148. infoContainer.appendChild(campaignIdContainer);
  149. }
  150.  
  151. if (bestSellersRankElement) {
  152. let rankContainer = document.createElement('div');
  153. rankContainer.appendChild(bestSellersRankElement);
  154. infoContainer.appendChild(rankContainer);
  155. }
  156.  
  157. // 将信息容器插入到标题元素的下一行
  158. titleElement.parentNode.insertBefore(infoContainer, titleElement.nextSibling);
  159. }
  160. });
  161. };
  162.  
  163. function createInfoContainer() {
  164. let container = document.createElement('div');
  165. container.style.display = 'block';
  166. container.style.flexDirection = 'row';
  167. container.style.alignItems = 'center';
  168. container.style.marginTop = '5px';
  169. return container;
  170. }
  171.  
  172. function createLabel(text, backgroundColor, foregroundColor) {
  173. let label = document.createElement('span');
  174. label.textContent = text;
  175. label.style.backgroundColor = backgroundColor;
  176. label.style.borderRadius = '50%';
  177. label.style.color = foregroundColor;
  178. label.style.display = 'inline-table';
  179. label.style.width = '25px';
  180. label.style.height = '25px';
  181. label.style.textAlign = 'center';
  182. label.style.marginLeft = '10px';
  183. label.style.marginRight = '5px';
  184. label.style.lineHeight = '25px';
  185. label.style.verticalAlign = 'middle';
  186. return label;
  187. }
  188.  
  189. function createIdElement(text, className) {
  190. let idElement = document.createElement('div');
  191. idElement.textContent = text;
  192. idElement.style.backgroundColor = '#DAA520';
  193. idElement.style.color = '#FFFFFF';
  194. idElement.style.fontWeight = 'bold';
  195. idElement.style.padding = '3px 6px';
  196. idElement.style.marginLeft = '10px';
  197. idElement.style.borderRadius = '4px';
  198. idElement.style.boxShadow = '0 1px 3px rgba(0, 0, 0, 0.3)';
  199. idElement.style.fontSize = '0.75rem';
  200. idElement.style.textAlign = 'center';
  201. idElement.style.verticalAlign = 'middle';
  202. idElement.style.display = 'inline-block';
  203. idElement.style.minWidth = '80px';
  204. idElement.style.height = '20px';
  205. idElement.style.lineHeight = '20px';
  206. idElement.classList.add(className);
  207. return idElement;
  208. }
  209.  
  210. let currentUrl = window.location.href;
  211.  
  212. const observer = new MutationObserver((mutations) => {
  213. let pageChanged = window.location.href !== currentUrl;
  214. if (pageChanged) {
  215. currentUrl = window.location.href;
  216. waitForContentLoaded().then(() => {
  217. applyLabelsAndIds();
  218. });
  219. }
  220. });
  221.  
  222. const waitForContentLoaded = () => {
  223. return new Promise((resolve) => {
  224. setTimeout(resolve, 500);
  225. });
  226. };
  227.  
  228. observer.observe(document.body, {childList: true, subtree: true});
  229.  
  230. applyLabelsAndIds();
  231.  
  232. })();