Greasy Fork

Greasy Fork is available in English.

BF1Tracker优化

去广告,自动获取玩家名, 地图名, 北京时间

当前为 2025-11-23 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         BF1Tracker优化
// @version      20251123
// @description  去广告,自动获取玩家名, 地图名, 北京时间
// @author       bilibili22
// @match        https://battlefieldtracker.com/bf1/*
// @icon         https://trackercdn.com/static-files/trackergg/production/dist/client/assets/0r7m9y2i.png
// @grant        GM_xmlhttpRequest
// @connect      ea-api.2788.pro
// @namespace    http://greasyfork.icu/users/1281680
// ==/UserScript==

(function () {
    'use strict'

    function removeAdContainers() {
        document.querySelector('.primisslate')?.remove()
        document.querySelector('.ad-container')?.remove()
        document.querySelector('.bordered-davert')?.remove()
        document.querySelector('[id^="google_ads_iframe_"]')?.remove()
    }

    removeAdContainers()

    const observer = new MutationObserver(removeAdContainers);

    observer.observe(document.body, { childList: true, subtree: true })


    const mapPrettyName = { MP_Amiens: '亚眠', MP_ItalianCoast: '帝国边境', MP_ShovelTown: '攻占托尔', MP_MountainFort: '格拉巴山', MP_Graveyard: '决裂', MP_FaoFortress: '法欧堡', MP_Chateau: '流血宴厅', MP_Scar: '圣康坦的伤痕', MP_Suez: '苏伊士', MP_Desert: '西奈沙漠', MP_Forest: '阿尔贡森林', MP_Giant: '庞然暗影', MP_Verdun: '凡尔登高地', MP_Trench: '尼维尔之夜', MP_Underworld: '法乌克斯要塞', MP_Fields: '苏瓦松', MP_Valley: '加利西亚', MP_Bridge: '勃鲁西洛夫关口', MP_Tsaritsyn: '察里津', MP_Ravines: '武普库夫山口', MP_Volga: '窝瓦河', MP_Islands: '阿尔比恩', MP_Beachhead: '海丽丝岬', MP_Harbor: '泽布吕赫', MP_Ridge: '阿奇巴巴', MP_River: '卡波雷托', MP_Hell: '帕斯尚尔', MP_Offensive: '索姆河', MP_Naval: '黑尔戈兰湾', MP_Blitz: '伦敦:夜袭', MP_London: '伦敦:灾祸', MP_Alps: '剃刀边缘' }
    const modePrettyName = { BreakthroughLarge: '行动模式', Breakthrough: '闪击行动', Conquest: '征服', TugOfWar: '前线', TeamDeathMatch: '团队死斗', Possession: '战争信鸽', Domination: '抢攻', Rush: '突袭', ZoneControl: '空降补给', AirAssault: '空中突击' }

    const xhrOpen = XMLHttpRequest.prototype.open
    XMLHttpRequest.prototype.open = function (method, url) {
        const xhr = this

        function block() {
            xhr.send = () => { }
            return xhrOpen.apply(xhr, arguments)
        }

        if (url.startsWith('https://api.tracker.gg/api/v2/bf1/standard/profile') && url.endsWith('?forceCollect=true')) return block()

        function hook(callback) {
            const getter = Object.getOwnPropertyDescriptor(XMLHttpRequest.prototype, 'responseText').get
            Object.defineProperty(xhr, 'responseText', {
                get: () => {
                    let resp = getter.call(xhr)
                    if (xhr.status !== 200) return resp
                    resp = callback(resp)
                    return resp
                },
            })
        }

        if (url.startsWith('https://api.tracker.gg/api/v2/bf1/standard/matches/origin/')
            || url.startsWith('https://api.tracker.gg/api/v2/bf1/standard/matches/psn/')
            || url.startsWith('https://api.tracker.gg/api/v2/bf1/standard/matches/xbl/')
        ) {
            hook((resp) => {
                resp = JSON.parse(resp)
                resp.data.matches.forEach(match => {
                    match.metadata.mapName = mapPrettyName[match.attributes.mapKey]
                    match.metadata.gamemodeName = modePrettyName[match.attributes.gamemodeKey.slice(0, -1)]
                })
                resp = JSON.stringify(resp)
                return resp
            })
        } else if (url.startsWith('https://api.tracker.gg/api/v2/bf1/standard/matches/')) {
            hook((resp) => {
                resp = JSON.parse(resp)
                resp.data.metadata.mapName = mapPrettyName[resp.data.attributes.mapKey]
                resp.data.metadata.gamemodeName = modePrettyName[resp.data.attributes.gamemodeKey.slice(0, -1)]
                const date = new Date(resp.data.metadata.timestamp).toLocaleString('zh-cn', { timeZone: 'Asia/Shanghai' })
                const ids = []
                resp.data.segments
                    .filter(data => data.type === 'player' && data.metadata.playerName === 'Unknown')
                    .forEach(player => {
                        player.metadata.playerName = `#${player.attributes.playerId}`
                        ids.push(+player.attributes.playerId)
                    })
                resp = JSON.stringify(resp)

                if (ids.length) {
                    GM_xmlhttpRequest({
                        url: `https://ea-api.2788.pro/v2/utils/getNamesByPersonaIds?personaIds=${ids.join(';')}`,
                        onload(xhr) {
                            if (xhr.status !== 200) {
                                console.error('获取玩家名失败', xhr)
                                return
                            }
                            const playerNames = JSON.parse(xhr.responseText)
                            const replace = async function () {
                                while (true) {
                                    const elements = Array.from(document.querySelectorAll('.player-header .info .name'))
                                    if (!elements.length) {
                                        await new Promise(resolve => setTimeout(resolve, 500))
                                        continue
                                    }
                                    for (const element of elements) {
                                        const text = element.textContent.trim()
                                        if (!text.startsWith('#')) continue
                                        const name = playerNames[text.slice(1)]
                                        if (!name) continue
                                        element.textContent = name
                                        element.href += name
                                        element.parentNode.replaceChild(element.cloneNode(true), element)
                                    }
                                    const timeElement = document.querySelector('.report-info .time')
                                    timeElement.textContent = date
                                    break
                                }
                            }
                            replace()
                        },
                    })
                }

                return resp
            })
        }
        return xhrOpen.apply(xhr, arguments)
    }
})()