您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
新球体育网(球探)手机端网页,比赛的分析页面里加入关键时间点的欧盘分析表格,注意提示里面的让球转换只是粗略值。
// ==UserScript== // @name 新球体育网欧盘分析 // @namespace http://dol.freevar.com/ // @version 0.6 // @description 新球体育网(球探)手机端网页,比赛的分析页面里加入关键时间点的欧盘分析表格,注意提示里面的让球转换只是粗略值。 // @author Dolphin // @match https://m.titan007.com/analy/Analysis/* // @match https://m.titan007.com/Analy/Analysis/* // @run-at document-idle // @grant GM_xmlhttpRequest // @license MIT // ==/UserScript== (function() { 'use strict'; // 全局变量存储解析后的赔率数据 let oddsData = {}; // 存储格式: {公司编号: {时间戳: {win, draw, lose}, ...}, ...} let allTimestamps = []; // 所有可用的时间戳 let tableData = []; // 表格数据 // 初始化函数 function init() { // 使用页面自带的scheduleId变量请求数据 const url = `https://txt.titan007.com/1x2/${scheduleId}.js`; GM_xmlhttpRequest({ method: "GET", url: url, onload: function(response) { if (response.status === 200) { parseOddsData(response.responseText); initializeTableData(); createUI(); } else { console.error("获取赔率数据失败:", response.statusText); } }, onerror: function(error) { console.error("请求赔率数据时发生错误:", error); } }); } // 解析赔率数据 function parseOddsData(data) { // 提取gameDetail数组 const gameDetailMatch = data.match(/var gameDetail=Array\((.*?)\);/); if (!gameDetailMatch) { console.error("无法解析gameDetail数据"); return; } const gameDetailStr = gameDetailMatch[1]; // 分割各个公司的数据 const companyEntries = gameDetailStr.split('","').map(item => { // 去除首尾引号 return item.replace(/^"/, '').replace(/"$/, ''); }); // 解析每个公司的数据 companyEntries.forEach(entry => { const [companyId, oddsInfo] = entry.split('^'); if (!oddsInfo) return; // 分割不同时间点的赔率 const oddsEntries = oddsInfo.split(';').filter(item => item.trim() !== ''); oddsData[companyId] = {}; oddsEntries.forEach(oddsEntry => { // 解析赔率条目 const parts = oddsEntry.split('|'); if (parts.length < 4) return; const [winOdds, drawOdds, loseOdds, timeStr] = parts; // 解析时间格式:月-日 时:分 const [datePart, timePart] = timeStr.split(' '); const [month, day] = datePart.split('-'); const [hour, minute] = timePart.split(':'); // 从数据中提取年份 const year = parts[7] || new Date().getFullYear(); // 创建时间戳 const timestamp = new Date(`${year}-${month}-${day}T${hour}:${minute}:00`).getTime(); // 存储赔率信息 oddsData[companyId][timestamp] = { win: parseFloat(winOdds), draw: parseFloat(drawOdds), lose: parseFloat(loseOdds) }; // 收集所有时间戳 if (!allTimestamps.includes(timestamp)) { allTimestamps.push(timestamp); } }); }); // 按时间戳排序 allTimestamps.sort((a, b) => a - b); } // 初始化表格数据 - 添加最早和最晚的时间点 function initializeTableData() { if (allTimestamps.length > 0) { // 添加最晚的时间点 addTimePointToTable(allTimestamps[allTimestamps.length - 1]); // 添加主客最近一场比赛开始和结束的时间点 addTimePointToTable(parseInt(jsonData.nearMatches.homeMatches.matches[0].matchTime) * 1000); addTimePointToTable(parseInt(jsonData.nearMatches.homeMatches.matches[0].matchTime) * 1000 + 3 * 3600000); addTimePointToTable(parseInt(jsonData.nearMatches.awayMatches.matches[0].matchTime) * 1000); addTimePointToTable(parseInt(jsonData.nearMatches.awayMatches.matches[0].matchTime) * 1000 + 3 * 3600000); // 添加最早的时间点 addTimePointToTable(allTimestamps[0]); } } // 添加时间点到表格数据 function addTimePointToTable(timestamp) { let totalWin = 0; let totalDraw = 0; let totalLose = 0; let companyCount = 0; // 计算该时间点前的赔率平均值 Object.values(oddsData).forEach(companyOdds => { // 找到该时间点或之前的最新赔率 const companyTimestamps = Object.keys(companyOdds).map(Number).sort((a, b) => b - a); const validTimestamp = companyTimestamps.find(ts => ts <= timestamp); if (validTimestamp) { const odds = companyOdds[validTimestamp]; totalWin += odds.win; totalDraw += odds.draw; totalLose += odds.lose; companyCount++; } }); if (companyCount > 0) { const avgWin = (totalWin / companyCount).toFixed(4); const avgDraw = (totalDraw / companyCount).toFixed(4); const avgLose = (totalLose / companyCount).toFixed(4); // 格式化时间显示 const date = new Date(timestamp); const formattedTime = `${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')} ${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`; // 检查该时间点是否已存在 const existingIndex = tableData.findIndex(item => item.timestamp === timestamp); if (existingIndex === -1) { // 添加到表格数据 tableData.push({ timestamp, formattedTime, companyCount, avgWin, avgDraw, avgLose }); // 按时间戳倒序排序(最新的在上面) tableData.sort((a, b) => b.timestamp - a.timestamp); // 更新表格显示 updateTable(); } } } // 添加用户自定义时间点 function addCustomTimePoint(timeStr) { // 解析用户输入的时间格式:YYYYMMDDHHmm if (timeStr.length !== 12) { alert("请输入正确的时间格式:YYYYMMDDHHmm"); return; } const year = timeStr.substr(0, 4); const month = timeStr.substr(4, 2); const day = timeStr.substr(6, 2); const hour = timeStr.substr(8, 2); const minute = timeStr.substr(10, 2); try { const timestamp = new Date(`${year}-${month}-${day}T${hour}:${minute}:00`).getTime(); if (isNaN(timestamp)) { alert("无效的时间格式"); return; } addTimePointToTable(timestamp); } catch (e) { alert("无效的时间格式"); console.error("时间解析错误:", e); } } // 创建用户界面 function createUI() { // 创建容器 const container = document.createElement('div'); container.style.border = '1px solid #888'; container.style.borderRadius = '5px'; container.style.textAlign = 'center'; container.style.fontSize = '16px'; // 创建输入框和按钮 const timeInput = document.createElement('input'); timeInput.type = 'number'; timeInput.style.fontSize = '16px'; timeInput.placeholder = '输入时间(YYYYMMDDHHmm)'; timeInput.style.padding = '4px'; timeInput.style.margin = '8px'; timeInput.style.border = '1px solid #888'; timeInput.style.borderRadius = '4px'; const addButton = document.createElement('button'); addButton.style.fontSize = '16px'; addButton.textContent = '添加时间'; addButton.style.padding = '6px 12px'; addButton.style.backgroundColor = '#48c'; addButton.style.color = 'white'; addButton.style.border = 'none'; addButton.style.borderRadius = '4px'; addButton.style.cursor = 'pointer'; addButton.addEventListener('click', () => { addCustomTimePoint(timeInput.value); timeInput.value = ''; }); container.appendChild(timeInput); container.appendChild(addButton); // 创建标题 const title = document.createElement('div'); title.style.background = '#eee'; title.textContent = '热门比赛欧亚转换(非精确):0.5球1.9⚽0.75球1.7⚽1球1.5⚽1.25球1.4⚽1.5球1.28⚽1.75球1.22⚽2球1.16'; container.appendChild(title); // 创建表格 const table = document.createElement('table'); table.id = 'oddsTable'; table.style.borderCollapse = 'collapse'; table.style.margin = '8px auto'; // 创建表头 const thead = document.createElement('thead'); const headerRow = document.createElement('tr'); headerRow.style.backgroundColor = '#48c'; headerRow.style.color = 'white'; const headers = ['公司数', '平均胜赔', '平均平赔', '平均负赔', '时间']; headers.forEach(headerText => { const th = document.createElement('th'); th.textContent = headerText; th.style.border = '1px solid #888'; headerRow.appendChild(th); }); thead.appendChild(headerRow); table.appendChild(thead); // 创建表体 const tbody = document.createElement('tbody'); tbody.id = 'oddsTableBody'; table.appendChild(tbody); container.appendChild(table); // 插入到页面中 const contentDiv = document.querySelector('div#content'); contentDiv.insertBefore(container, contentDiv.firstChild); // 初始更新表格内容 updateTable(); } // 更新表格内容 function updateTable() { const tbody = document.getElementById('oddsTableBody'); if (!tbody) return; // 清空表格 tbody.innerHTML = ''; // 添加数据行 tableData.forEach((rowData) => { const row = document.createElement('tr'); // 公司数量 const countCell = document.createElement('td'); countCell.textContent = rowData.companyCount; countCell.style.border = '1px solid #888'; row.appendChild(countCell); // 平均胜赔 const winCell = document.createElement('td'); winCell.textContent = rowData.avgWin; winCell.style.border = '1px solid #888'; row.appendChild(winCell); // 平均平赔 const drawCell = document.createElement('td'); drawCell.textContent = rowData.avgDraw; drawCell.style.border = '1px solid #888'; row.appendChild(drawCell); // 平均负赔 const loseCell = document.createElement('td'); loseCell.textContent = rowData.avgLose; loseCell.style.border = '1px solid #888'; row.appendChild(loseCell); // 时间 const timeCell = document.createElement('td'); timeCell.textContent = rowData.formattedTime; timeCell.style.border = '1px solid #888'; row.appendChild(timeCell); tbody.appendChild(row); }); // 设置颜色标注 setOddsColorCoding(); } // 设置赔率颜色标注 - 比较上下行赔率 function setOddsColorCoding() { const rows = document.querySelectorAll('#oddsTableBody tr'); if (rows.length < 2) return; // 从第二行开始,与上一行比较 for (let i = 1; i < rows.length; i++) { const currentRow = rows[i]; const prevRow = rows[i - 1]; // 获取当前行和上一行的赔率单元格 const currentWin = parseFloat(currentRow.cells[1].textContent); const currentDraw = parseFloat(currentRow.cells[2].textContent); const currentLose = parseFloat(currentRow.cells[3].textContent); const prevWin = parseFloat(prevRow.cells[1].textContent); const prevDraw = parseFloat(prevRow.cells[2].textContent); const prevLose = parseFloat(prevRow.cells[3].textContent); // 比较并设置颜色 // 上一行相比当前行(上一行是更新的时间点) if (prevWin > currentWin) { prevRow.cells[1].style.backgroundColor = '#fbb'; // 红色背景表示上涨 } else if (prevWin < currentWin) { prevRow.cells[1].style.backgroundColor = '#bfb'; // 绿色背景表示下跌 } else { prevRow.cells[1].style.backgroundColor = ''; } if (prevDraw > currentDraw) { prevRow.cells[2].style.backgroundColor = '#fbb'; } else if (prevDraw < currentDraw) { prevRow.cells[2].style.backgroundColor = '#bfb'; } else { prevRow.cells[2].style.backgroundColor = ''; } if (prevLose > currentLose) { prevRow.cells[3].style.backgroundColor = '#fbb'; } else if (prevLose < currentLose) { prevRow.cells[3].style.backgroundColor = '#bfb'; } else { prevRow.cells[3].style.backgroundColor = ''; } } } // 启动脚本 init(); })();