PageSourceSearch

https://travly.io/wp-content/plugins/sport-wp-plugin-livescore-bn/assets/js/sport-m.js?ver=2.3.6

js travly.io collected 2026-10-09 21:41:43 UTC 11,317 bytes, 336 lines download raw bytes

1(function () {
2  "use strict";
3
4  // 1. CONFIG: SELECTOR ITEM (Giữ nguyên theo yêu cầu)
5  const SELECTORS_PRESET = [
6    ".result_table-row", // Bongdanet ket qua
7    ".table-wrapper tr", // Bongdanet lich thi dau
8    ".match_table-row", // Bongdanet
9    ".bds-match-table-match", // Bongdaso
10    ".w7m_score-table--row", // 7M v1
11    ".w7m_table-tr.is_match", // 7M v2
12    ".match_table-tbody .match_table-row:not(.is_league)", // Bongdawap
13    ".bongdawap_match-item", // Bongdawap
14    ".table-row-mb", // Bongdawap mobile
15    ".bet-match-item-repeated", // bongdako_6in1
16    ".match-list-box-repeated-sm", // bongdako_6in1 mobile
17    ".new-home-tr", // bongdako_fixture, bongdako_result
18    "#table_live .tds", // bongdalu
19    ".league-matches .match-item", // Widget pro
20    ".livescore-tbl-tbody .tbl-rows.tbl-match",
21    ".fixture-table .match-row",
22    ".odd-table .table-match-box",
23    ".match-list-scroll .match-row",
24    ".bdk-table .bdk-match-row",
25    ".page-schedule tbody tr", // Trang lịch thi đấu league plugin v1
26  ];
27
28  // 2. CONFIG: SELECTOR TABLE WRAPPER (Mới thêm)
29  // Dùng để xác định container cha nhằm đếm số lượng thay đổi
30  const WRAPPER_SELECTORS = [
31    ".w7m_table", // 7M
32    ".w7m_score-table", // 7M
33    ".bds-match-table", // Bongdaso
34    ".match_table-tbody", // Bongdanet
35    ".common-table", // Bongdanet
36    ".result_table-tbody", // Bongdanet
37    ".match-table-mb", // Bongdawap mobile
38    ".bet-match-list", // bongdako_6in1
39    "#table_live", // bongdako_fixture, bongdako_result
40    ".match-list-sm", // bongdako_6in1 mobile
41    ".league-matches", // Widget pro
42    ".livescore-tbl-tbody",
43    ".fixture-table",
44    ".odd-table",
45    ".match-list-scroll",
46    ".bdk-table",
47    ".page-schedule tbody", // Trang lịch thi đấu league plugin v1
48  ];
49
50  let pollingInterval = null;
51  let lastItemCount = -1; // Lưu trữ số lượng item lần trước
52
53  // --- DOM HELPERS (raw JS, fault-tolerant) ---
54  // querySelectorAll throws on invalid selectors (e.g. "/"); swallow it
55  // so one bad selector can't break the whole poller.
56  function qsa(selector, root) {
57    if (!selector) return [];
58    try {
59      return Array.prototype.slice.call(
60        (root || document).querySelectorAll(selector),
61      );
62    } catch (e) {
63      return [];
64    }
65  }
66
67  function matchesSelector(el, selector) {
68    if (!el || !selector) return false;
69    try {
70      return el.matches(selector);
71    } catch (e) {
72      return false;
73    }
74  }
75
76  // Find ".sport-m" descendants across a list of container elements.
77  function findInContainers(containers, selector) {
78    const out = [];
79    for (let i = 0; i < containers.length; i++) {
80      const found = qsa(selector, containers[i]);
81      for (let j = 0; j < found.length; j++) out.push(found[j]);
82    }
83    return out;
84  }
85
86  // --- UTILS ---
87  function triggerReviveRefresh() {
88    try {
89      var firstInsTag = document.querySelector("ins[data-revive-id]");
90      if (firstInsTag) {
91        var reviveId = firstInsTag.getAttribute("data-revive-id");
92        if (window.reviveAsync && window.reviveAsync[reviveId]) {
93          window.reviveAsync[reviveId].dispatchEvent("refresh");
94        }
95      }
96    } catch (e) {}
97  }
98
99  // --- MAIN INIT ---
100  function init() {
101    if (typeof SportAdsObj === "undefined") return;
102    const config = SportAdsObj;
103    const currentPage = config.current_page;
104
105    if (!currentPage || !config.pages[currentPage]) return;
106
107    const isMobile = window.innerWidth < 768;
108    const deviceType = isMobile ? "mobile" : "desktop";
109    const pageData = config.pages[currentPage][deviceType];
110
111    const configSelector = pageData.selector;
112    const wrapperSelector = pageData.wrapper_selector;
113    const banners = pageData.banners;
114    const offset = parseInt(pageData.offset) || 0;
115    const density = parseInt(pageData.density) || 3;
116
117    if (config.debug_mode)
118      console.log("🔍 [SportAds] Checking selector for page:", banners);
119    if (!configSelector || !banners || banners.length === 0) return;
120
121    let targetSearchList =
122      configSelector === "default" ? SELECTORS_PRESET : [configSelector];
123
124    if (config.debug_mode) console.log("🏁 [SportAds] Init");
125
126    findActiveSelector(targetSearchList, function (foundSelector) {
127      if (config.debug_mode)
128        console.log(`🎯 Selector detected: "${foundSelector}"`);
129      startAdsPoller(
130        foundSelector,
131        wrapperSelector,
132        banners,
133        offset,
134        density,
135        config.debug_mode,
136      );
137    });
138  }
139
140  if (document.readyState === "loading") {
141    document.addEventListener("DOMContentLoaded", init);
142  } else {
143    init();
144  }
145
146  function findActiveSelector(searchList, callback) {
147    const initPoller = setInterval(() => {
148      let found = null;
149      for (let i = 0; i < searchList.length; i++) {
150        if (qsa(searchList[i]).length > 0) {
151          found = searchList[i];
152          break;
153        }
154      }
155      if (found) {
156        clearInterval(initPoller);
157        callback(found);
158      }
159    }, 200);
160    setTimeout(() => clearInterval(initPoller), 30000);
161  }
162
163  /**
164   * POLLER CHÍNH (Kiểm tra mỗi 1s)
165   */
166  function startAdsPoller(
167    itemSelector,
168    customWrapper,
169    banners,
170    offset,
171    density,
172    debugMode,
173  ) {
174    if (pollingInterval) clearInterval(pollingInterval);
175
176    pollingInterval = setInterval(function () {
177      const items = qsa(itemSelector);
178
179      // Nếu không có item nào -> Có thể đang load -> Bỏ qua
180      if (items.length === 0) {
181        lastItemCount = 0;
182        return;
183      }
184
185      // --- LOGIC 1: TÌM CONTAINER CHA TỪ LIST WRAPPER ---
186      let containers = [];
187
188      let wrapperList = customWrapper
189        ? [customWrapper].concat(WRAPPER_SELECTORS)
190        : WRAPPER_SELECTORS;
191
192      // Ưu tiên tìm wrapper theo list user cung cấp
193      for (let i = 0; i < wrapperList.length; i++) {
194        const matched = qsa(wrapperList[i]);
195        if (matched.length > 0) {
196          containers = matched;
197          break;
198        }
199      }
200      // Fallback: Nếu không tìm thấy wrapper trong list, lấy parent trực tiếp của item
201      if (containers.length === 0) {
202        const parent = items[0].parentElement;
203        if (parent) containers = [parent];
204      }
205
206      // --- LOGIC 2: KIỂM TRA BIẾN ĐỘNG SỐ LƯỢNG (DIFF CHECK) ---
207      const currentCount = items.length;
208
209      // Nếu lần đầu chạy (lastItemCount = -1), gán giá trị hiện tại
210      if (lastItemCount === -1) lastItemCount = currentCount;
211
212      const diff = Math.abs(currentCount - lastItemCount);
213
214      // Điều kiện Reset: Thay đổi quá 5 item (Vue update list, load more...)
215      const isHugeChange = diff > 5;
216
217      // Điều kiện Mất Ads: Không tìm thấy banner nào
218      const isAdsMissing = findInContainers(containers, ".sport-m").length === 0;
219
220      if (isHugeChange || isAdsMissing) {
221        if (debugMode) {
222          if (isHugeChange)
223            console.log(
224              `🔄 List changed significantly (Diff: ${diff}). Resetting Ads...`,
225            );
226          if (isAdsMissing && !isHugeChange)
227            console.log("♻️ Ads missing. Injecting...");
228        }
229
230        // 1. Clean up banner cũ (nếu do biến động số lượng)
231        const oldAds = findInContainers(containers, ".sport-m");
232        for (let i = 0; i < oldAds.length; i++) {
233          if (oldAds[i].parentNode) oldAds[i].parentNode.removeChild(oldAds[i]);
234        }
235
236        // 2. Reset flag trên các item (để cho phép chèn lại)
237        for (let i = 0; i < items.length; i++) {
238          items[i].classList.remove("ads-injected-processed");
239        }
240
241        // 3. Inject lại từ đầu
242        injectAdsLogic(itemSelector, banners, offset, density, debugMode);
243
244        // 4. Cập nhật số lượng mới
245        lastItemCount = currentCount;
246      }
247      // Nếu thay đổi nhỏ (<= 5 item) -> Cập nhật lại số lượng để lần sau so sánh tiếp
248      else {
249        lastItemCount = currentCount;
250      }
251    }, 1000);
252  }
253
254  /**
255   * LOGIC CHÈN BANNER (FIXED WIDTH)
256   */
257  function injectAdsLogic(selector, banners, offset, density, debugMode) {
258    const items = qsa(selector);
259    const totalItems = items.length;
260
261    if (totalItems === 0) return;
262
263    // Safety Check: Chỉ chèn nếu thực sự sạch sẽ (đã clean ở trên rồi nhưng check lại cho chắc)
264    if (qsa(".sport-m").length > 0) return;
265
266    // Đánh dấu item đầu tiên
267    if (items[0].classList.contains("ads-injected-processed")) return;
268    for (let i = 0; i < items.length; i++) {
269      items[i].classList.add("ads-injected-processed");
270    }
271
272    // Check Table Layout
273    let isTableLayout = false;
274    if (matchesSelector(items[0], "tr")) {
275      isTableLayout = true;
276    }
277
278    if (banners.length > 0) {
279      let count = 0;
280      banners.forEach(function (banner, index) {
281        let insertIndex = offset + index * density;
282        if (insertIndex >= totalItems) return;
283
284        let contentHtml = "";
285
286        let innerHtml = "";
287        if (banner.html_code && banner.html_code.trim() !== "") {
288          innerHtml = banner.html_code;
289        } else if (banner.image && banner.image.url) {
290          innerHtml +=
291            '<div style="text-align:center; margin: 0; width: 100%;">';
292          if (banner.link && banner.link !== "#")
293            innerHtml +=
294              '<a href="' +
295              banner.link +
296              '" target="_blank" style="display:block; width: 100%;">';
297          innerHtml +=
298            '<img src="' +
299            banner.image.url +
300            '" style="max-width:100%; height:auto; display:inline-block; vertical-align: middle;" />';
301          if (banner.link && banner.link !== "#") innerHtml += "</a>";
302          innerHtml += "</div>";
303        }
304
305        if (isTableLayout) {
306          contentHtml = `
307                        <tr class="sport-m" style="display: table-row; width: 100%;">
308                            <td colspan="100" style="display: table-cell; padding: 0; text-align: center; background-color: transparent; border: none; width: 100%;">
309                                ${innerHtml}
310                            </td>
311                        </tr>
312                    `;
313        } else {
314          contentHtml = `<div class="sport-m" style="width: 100%; clear: both;">${innerHtml}</div>`;
315        }
316
317        if (innerHtml !== "") {
318          if (insertIndex === 0) {
319            items[0].insertAdjacentHTML("beforebegin", contentHtml);
320          } else {
321            items[insertIndex - 1].insertAdjacentHTML("afterend", contentHtml);
322          }
323          count++;
324        }
325      });
326
327      if (debugMode && count > 0) console.log(`✅ Injected ${count} banners.`);
328    }
329
330    triggerReviveRefresh();
331  }
332
333  window.addEventListener("load", function () {
334    setTimeout(triggerReviveRefresh, 1500);
335  });
336})();

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.