1document.addEventListener("DOMContentLoaded", function () { 2 const CONFIG = { 3 // èªç¤¾PHP API 4 proxyUrl: "https://o-ki.co.jp/cgi-bin/get_star-rating.cgi", 5 6 // ååä¸è¦§ã®ååããã㯠7 targetSelector: ".column4, .column5", 8 9 // ã¬ãã¥ã¼è¡¨ç¤ºä½ç½® 10 insertPosition: ".price, .sp_price", 11 12 // åæå徿° 13 maxConcurrent: 3, 14 15 // æªãã£ãã·ã¥æã®åå¾éé(ms) 16 requestInterval: 1100, 17 }; 18 19 const queue = []; 20 let activeRequests = 0; 21 22 // 表示é åã«è¿ã¥ããååã ãåå¾ãã 23 const observer = new IntersectionObserver( 24 (entries) => { 25 entries.forEach((entry) => { 26 if (!entry.isIntersecting) return; 27 28 const element = entry.target; 29 const itemCode = getItemCode(element); 30 31 if (itemCode) { 32 enqueueFetch(itemCode, element); 33 } 34 35 observer.unobserve(element); 36 }); 37 }, 38 { 39 rootMargin: "100px", 40 }, 41 ); 42 43 // å¤é¨ããåå®è¡ã§ããããã«ãã 44 window.initStarRating = function (targets) { 45 const elements = targets || document.querySelectorAll(CONFIG.targetSelector); 46 47 elements.forEach((el) => { 48 if (!el.querySelector(".sps-review-rating")) { 49 observer.observe(el); 50 } 51 }); 52 }; 53 54 // ååã³ã¼ãåå¾ 55 function getItemCode(element) { 56 const anchor = element.querySelector("h2 a, h3 a"); 57 58 if (!anchor) return null; 59 60 const href = anchor.getAttribute("href"); 61 62 if (!href) return null; 63 64 const match = href.match(/\/SHOP\/(.+)\.html/); 65 66 return match ? match[1] : null; 67 } 68 69 // ãã¥ã¼è¿½å 70 function enqueueFetch(itemCode, element) { 71 const cacheKey = "sps_review_" + itemCode; 72 73 const cachedData = sessionStorage.getItem(cacheKey); 74 75 // ãã¼ã¸å ãã£ãã·ã¥ãããã°å³è¡¨ç¤º 76 if (cachedData) { 77 try { 78 const data = JSON.parse(cachedData); 79 80 displayReview(element, data.score, data.count); 81 82 return; 83 } catch (e) { 84 sessionStorage.removeItem(cacheKey); 85 } 86 } 87 88 queue.push({ 89 itemCode, 90 element, 91 }); 92 93 processQueue(); 94 } 95 96 // APIåå¾å¦ç 97 async function processQueue() { 98 if (activeRequests >= CONFIG.maxConcurrent || queue.length === 0) { 99 return; 100 } 101 102 activeRequests++; 103 104 const { itemCode, element } = queue.shift(); 105 106 try { 107 const url = `${CONFIG.proxyUrl}?item_code=${encodeURIComponent(itemCode)}`; 108 109 const response = await fetch(url); 110 111 if (response.ok) { 112 const data = await response.json(); 113 114 sessionStorage.setItem("sps_review_" + itemCode, JSON.stringify(data)); 115 116 displayReview(element, data.score, data.count); 117 } 118 119 activeRequests--; 120 121 // 次ã®åå¾ 122 setTimeout(() => { 123 processQueue(); 124 }, CONFIG.requestInterval); 125 } catch (error) { 126 activeRequests--; 127 128 setTimeout(() => { 129 processQueue(); 130 }, CONFIG.requestInterval); 131 } 132 } 133 134 // ã¬ãã¥ã¼è¡¨ç¤º 135 function displayReview(element, score, count) { 136 if (element.querySelector(".sps-review-rating")) { 137 return; 138 } 139 140 const priceElement = element.querySelector(CONFIG.insertPosition); 141 142 if (!priceElement) return; 143 144 const container = document.createElement("div"); 145 146 container.className = "sps-review-rating"; 147 148 container.innerHTML = createReviewHtml(score, count); 149 150 priceElement.insertAdjacentElement("afterend", container); 151 } 152 153 // 表示HTML使 154 function createReviewHtml(score, count) { 155 score = Number(score) || 0; 156 157 count = Number(count) || 0; 158 159 const fillWidth = (score / 5) * 100; 160 161 const displayScore = score.toFixed(1); 162 163 return ` 164 165 <div class="box-star"> 166 167 <div class="sps-stars-outer"> 168 169 â â â â â 170 171 <div class="sps-stars-inner" 172 style="width:${fillWidth}%;"> 173 â â â â â 174 </div> 175 176 </div> 177 178 179 <div class="sps-stars-num"> 180
181 <span class="sps-review-text"> 182 ${displayScore} 183 </span> 184 185 <span class="sps-review-count"> 186 ${count}ä»¶ 187 </span> 188 189 </div> 190 191 </div> 192 193 `; 194 } 195 196 // ãã¼ã¸èªã¿è¾¼ã¿å¾éå§ 197 window.addEventListener("load", () => { 198 setTimeout(() => { 199 window.initStarRating(); 200 }, 800); 201 }); 202});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.