新球体育网欧赔分析

新球体育网(球探)手机端网页,比赛的分析页面里按开盘顺序列出所有公司,选择所需的公司列出各个时间点的欧赔作对比。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         新球体育网欧赔分析
// @namespace    http://dol.freevar.com/
// @version      0.9
// @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';

    // 请求赔率数据
    GM_xmlhttpRequest({
        method: 'GET',
        url: `https://txt.titan007.com/1x2/${scheduleId}.js`,
        onload: function(response) {
            if (response.status === 200) {
                processOddsData(response.responseText);
            } else {
                console.log('请求赔率数据失败:', response.status);
            }
        },
        onerror: function(error) {
            alert('请求赔率数据出错:', error);
        }
    });

    function processOddsData(data) {
        // 解析公司数据
        const companyMap = {};
        const companyGameMatch = data.match(/var game=Array\((.*?)\);/);
        if (companyGameMatch && companyGameMatch[1]) {
            const companyData = companyGameMatch[1].split('","').map(item => item.replace(/"/g, ''));
            companyData.forEach(item => {
                const fields = item.split('|');
                if (fields.length >= 3) {
                    const companyId = fields[1];
                    const companyName = fields[2];
                    companyMap[companyId] = companyName;
                }
            });
        }

        // 解析赔率详细数据
        const oddsDetailMatch = data.match(/var gameDetail=Array\((.*?)\);/);
        if (!oddsDetailMatch || !oddsDetailMatch[1]) {
            console.log('未找到赔率详细数据');
            return;
        }

        const oddsData = {};
        const detailData = oddsDetailMatch[1].split('","').map(item => item.replace(/"/g, ''));

        detailData.forEach(item => {
            const [companyId, oddsString] = item.split('^');
            if (oddsString) {
                const oddsRecords = oddsString.split(';').filter(record => record.trim());
                oddsData[companyId] = oddsRecords.map(record => {
                    const fields = record.split('|');
                    if (fields.length >= 8) {
                        return {
                            win: parseFloat(fields[0]),
                            draw: parseFloat(fields[1]),
                            lose: parseFloat(fields[2]),
                            time: fields[3], // 月-日 时:分
                            year: fields[7]
                        };
                    }
                    return null;
                }).filter(record => record !== null);
            }
        });

        // 创建UI界面
        createUI(companyMap, oddsData);
    }

    function createUI(companyMap, oddsData) {
        const contentDiv = document.querySelector('div#content');
        if (!contentDiv) return;

        // 创建容器
        const container = document.createElement('div');
        container.id = 'ctrlPanel';
        container.style.fontSize = '16px';
        container.style.textAlign = 'center';

        // 按最早赔率时间排序公司
        const sortedCompanies = Object.keys(companyMap).sort((a, b) => {
            const timeA = getEarliestTime(oddsData[a]);
            const timeB = getEarliestTime(oddsData[b]);
            return timeA - timeB;
        });

        // 创建公司复选框
        sortedCompanies.forEach(companyId => {
            const companyName = companyMap[companyId];
            const checkboxContainer = document.createElement('div');
            checkboxContainer.style.display = 'inline-block';
            checkboxContainer.style.margin = '5px';

            const checkbox = document.createElement('input');
            checkbox.type = 'checkbox';
            checkbox.value = companyId;
            checkbox.id = `company_${companyId}`;
            checkbox.checked = false;
            checkbox.style.position = 'initial';

            const span = document.createElement('span');
            span.textContent = companyName;

            //重点公司标红
            const keyCompanies = ['Pinnacle', '18Bet', 'Vcbet', '188bet', 'Bet 365', 'Wewbet', 'Easybets', 'Marathonbet'];
            if (keyCompanies.includes(companyName)) span.style.color = '#f00';

            span.style.cursor = 'pointer';
            span.onclick = function () { checkbox.checked = !checkbox.checked; };

            checkboxContainer.appendChild(checkbox);
            checkboxContainer.appendChild(span);
            container.appendChild(checkboxContainer);
        });

        // 创建按钮
        const button = document.createElement('button');
        button.textContent = '欧赔概率';
        button.style.padding = '8px 10px';
        button.style.backgroundColor = '#007bff';
        button.style.color = 'white';
        button.style.border = 'none';
        button.style.borderRadius = '4px';
        button.style.cursor = 'pointer';

        button.onclick = () => {
            showOddsProbability(companyMap, oddsData);
        };

        container.appendChild(document.createElement('br'));
        container.appendChild(button);

        // 插入到页面中
        contentDiv.insertBefore(container, contentDiv.firstChild);
    }

    function getEarliestTime(oddsRecords) {
        if (!oddsRecords || oddsRecords.length === 0) return Infinity;

        return Math.min(...oddsRecords.map(record => {
            const [monthDay, time] = record.time.split(' ');
            const [month, day] = monthDay.split('-').map(Number);
            const [hour, minute] = time.split(':').map(Number);
            // 使用记录中的年份
            const year = parseInt(record.year);
            return new Date(year, month - 1, day, hour, minute).getTime();
        }));
    }

    function showOddsProbability(companyMap, oddsData) {
        // 获取选中的公司
        const selectedCompanies = Array.from(document.querySelectorAll('div#ctrlPanel input[type="checkbox"]:checked'))
            .map(checkbox => checkbox.value);

        if (selectedCompanies.length === 0) {
            alert('请至少选择一家公司');
            return;
        }

        // 获取比赛时间
        const homeMatchTime = parseInt(jsonData.nearMatches.homeMatches.matches[0].matchTime) * 1000;
        const awayMatchTime = parseInt(jsonData.nearMatches.awayMatches.matches[0].matchTime) * 1000;
        const homeEndTime = homeMatchTime + 2 * 60 * 60 * 1000;
        const awayEndTime = awayMatchTime + 2 * 60 * 60 * 1000;

        // 收集所有时间点
        const allTimePoints = new Set();
        const companyColors = {};
        const colorPalette = ['#000000', '#FF0000', '#0000FF', '#008000', '#800080', '#FFA500', '#00FFFF', '#FF00FF', '#800000', '#008080'];

        selectedCompanies.forEach((companyId, index) => {
            companyColors[companyId] = colorPalette[index % colorPalette.length];
            if (oddsData[companyId]) {
                oddsData[companyId].forEach(record => {
                    const timestamp = convertToTimestamp(record.time, record.year);
                    allTimePoints.add(timestamp);
                });
            }
        });

        // 添加必须的时间点
        allTimePoints.add(homeMatchTime);
        allTimePoints.add(homeEndTime);
        allTimePoints.add(awayMatchTime);
        allTimePoints.add(awayEndTime);

        // 排序时间点
        const sortedTimePoints = Array.from(allTimePoints).sort((a, b) => a - b);

        // 创建表格
        const table = document.createElement('table');
        table.style.borderCollapse = 'collapse';
        table.style.margin = '10px auto 0';

        // 表头
        const thead = document.createElement('thead');
        const headerRow = document.createElement('tr');
        ['时间', '胜概率', '平概率', '负概率', '公司', '返还率'].forEach(text => {
            const th = document.createElement('th');
            th.textContent = text;
            th.style.border = '1px solid #888';
            th.style.backgroundColor = '#eee';
            headerRow.appendChild(th);
        });
        thead.appendChild(headerRow);
        table.appendChild(thead);

        // 表格内容
        const tbody = document.createElement('tbody');

        sortedTimePoints.forEach(timestamp => {
            // 检查是否在比赛期间
            const isDuringHomeMatch = (timestamp >= homeMatchTime && timestamp <= homeEndTime);
            const isDuringAwayMatch = (timestamp >= awayMatchTime && timestamp <= awayEndTime);
            const isDuringMatches = isDuringHomeMatch || isDuringAwayMatch;

            let hasDataForThisTime = false;

            // 为每个选中的公司创建行
            selectedCompanies.forEach(companyId => {
                const companyOdds = oddsData[companyId];
                if (!companyOdds) return;

                const record = companyOdds.find(r =>
                    convertToTimestamp(r.time, r.year) === timestamp
                );

                if (record) {
                    hasDataForThisTime = true;
                    const row = createDataRow(record, companyMap[companyId], companyColors[companyId], isDuringMatches);
                    tbody.appendChild(row);
                }
            });

            // 如果没有数据但这是必须的时间点,创建空行
            if (!hasDataForThisTime && [homeMatchTime, homeEndTime, awayMatchTime, awayEndTime].includes(timestamp)) {
                const row = document.createElement('tr');
                if (isDuringMatches) {
                    row.style.backgroundColor = '#ffb';
                }

                const timeCell = document.createElement('td');
                timeCell.style.border = '1px solid #888';
                timeCell.textContent = formatTimestamp(timestamp);
                row.appendChild(timeCell);

                // 空单元格
                for (let i = 0; i < 5; i++) {
                    const emptyCell = document.createElement('td');
                    emptyCell.style.border = '1px solid #888';
                    row.appendChild(emptyCell);
                }

                tbody.appendChild(row);
            }
        });

        table.appendChild(tbody);

        // 移除已存在的表格
        const existingTable = document.querySelector('#oddsProbabilityTable');
        if (existingTable) {
            existingTable.remove();
        }

        table.id = 'oddsProbabilityTable';

        // 插入表格
        const container = document.querySelector('div#ctrlPanel');
        container.appendChild(table);
    }

    function createDataRow(record, companyName, color, isDuringMatches) {
        const row = document.createElement('tr');
        row.style.color = color;

        if (isDuringMatches) {
            row.style.backgroundColor = '#ffb';
        }

        // 计算概率和返还率
        const returnRate = 1/(1/record.win+1/record.draw+1/record.lose);

        const winProb = (returnRate / record.win * 100).toFixed(2);
        const drawProb = (returnRate / record.draw * 100).toFixed(2);
        const loseProb = (returnRate / record.lose * 100).toFixed(2);

        // 时间单元格
        const timeCell = document.createElement('td');
        timeCell.style.border = '1px solid #888';
        timeCell.textContent = record.time;
        row.appendChild(timeCell);

        // 概率单元格
        [winProb, drawProb, loseProb].forEach(prob => {
            const probCell = document.createElement('td');
            probCell.style.border = '1px solid #888';
            probCell.textContent = prob;
            row.appendChild(probCell);
        });

        // 公司单元格
        const companyCell = document.createElement('td');
        companyCell.style.border = '1px solid #888';
        companyCell.textContent = companyName;
        row.appendChild(companyCell);

        // 返还率单元格
        const returnCell = document.createElement('td');
        returnCell.style.border = '1px solid #888';
        returnCell.textContent = (returnRate * 100).toFixed(2);
        row.appendChild(returnCell);

        return row;
    }

    function convertToTimestamp(timeStr, yearStr) {
        const [monthDay, time] = timeStr.split(' ');
        const [month, day] = monthDay.split('-').map(Number);
        const [hour, minute] = time.split(':').map(Number);
        const year = parseInt(yearStr);
        return new Date(year, month - 1, day, hour, minute).getTime();
    }

    function formatTimestamp(timestamp) {
        const date = new Date(timestamp);
        const month = (date.getMonth() + 1).toString().padStart(2, '0');
        const day = date.getDate().toString().padStart(2, '0');
        const hours = date.getHours().toString().padStart(2, '0');
        const minutes = date.getMinutes().toString().padStart(2, '0');
        return `${month}-${day} ${hours}:${minutes}`;
    }
})();