transfermarkt match exporter

exports match data from transfermarkt match reports

// ==UserScript==
// @name         transfermarkt match exporter
// @description  exports match data from transfermarkt match reports
// @namespace    http://tampermonkey.net/
// @version      1.3
// @author       You
// @match        https://www.transfermarkt.com/*/spielbericht/*
// @match        https://www.transfermarkt.de/*/spielbericht/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=transfermarkt.com
// @grant        GM_addStyle
// @grant        GM_xmlhttpRequest
// @grant        GM_setClipboard
// @require      https://unpkg.com/x-frame-bypass@latest/x-frame-bypass.js
// @license      GPLv3
// ==/UserScript==

let btn = document.createElement("button");
btn.id = "floatingButton";
btn.textContent = "Export";
btn.onclick = async function () {
  btn.textContent = "Loading...";
  const report = {};

  await generateLineupData();
  await generateMatchCourseData();

  //document
  //  .getElementById("4373743")
  //  .shadowRoot.querySelector("li.svelte-zxas2b:nth-child(1) > a:nth-child(1)")
  //  .click();
  //await delay(1000);
  //await generateMatchCourseData();

  //const ground = document
  //  .querySelector("span.hide-for-small > a:nth-child(1)")
  //  .innerText.trim();

  //const attendanceContainer = document.querySelector(
  //  "span.hide-for-small > strong:nth-child(2)",
  //);
  //if (attendanceContainer)
  //  report.attendance = attendanceContainer.innerText.split(": ")[1].trim();

  //report.ground = ground;
  report.events = {
    substitutions: subEvents,
    goals: goalEvents,
    cards: cardEvents,
  };
  report.players = players;
  document.getElementById("loadingSpinner").style.display = "none";
  document.getElementById("popup-body").innerText = JSON.stringify(report);
  GM_setClipboard(JSON.stringify(report), "json");
  if (report.players.length > 0) {
    btn.style.backgroundColor = "#28a745";
    btn.textContent = "Copied!";
    setTimeout(() => {
      btn.textContent = "Export";
      btn.style.backgroundColor = "#007BFF";
    }, 1500);
  }
};

function getPlayerId(url) {
  if (url.includes("player-id/")) {
    return url.split("player-id/")[1];
  }

  return url.split("userid/")[1];
}

function findPlayerIdByName(name) {
  const player = players.find((p) => p.name === name);
  return player ? player.id : null;
}

const players = [];
const subEvents = [];
const goalEvents = [];
const cardEvents = [];

function fetchPlayers(doc, playerTable, home, substitutes = false) {
  const table = doc.querySelector(playerTable);
  Array.from(table.rows).forEach((row) => {
    let id = row.querySelector("a.wichtig").href;
    players.push({
      id,
      name: row.querySelector("a.wichtig").innerText,
      number: row.querySelector(".rn_nummer").innerText.trim(),
      home,
      sub: substitutes,
    });
  });
}

async function generateLineupData() {
  return new Promise((resolve) => {
    players.length = 0;
    const href = document
      .querySelector("tm-subnavigation[section=spielbericht]")
      .shadowRoot.querySelector(
        "li.svelte-zxas2b:nth-child(2) > a:nth-child(1)",
      ).href;

    GM_xmlhttpRequest({
      method: "GET",
      url: href,
      onload: async function (response) {
        let parser = new DOMParser();
        let doc = parser.parseFromString(response.responseText, "text/html");
        // home starting
        fetchPlayers(
          doc,
          "div.row:nth-child(8) > div:nth-child(1) > div:nth-child(1) > div:nth-child(2) > table:nth-child(1)",
          true,
          false,
        );
        // away starting
        fetchPlayers(
          doc,
          "div.row:nth-child(8) > div:nth-child(2) > div:nth-child(1) > div:nth-child(2) > table:nth-child(1)",
          false,
          false,
        );
        // home subs
        fetchPlayers(
          doc,
          "div.row:nth-child(9) > div:nth-child(1) > div:nth-child(1) > div:nth-child(2) > table:nth-child(1)",
          true,
          true,
        );
        // away subs
        fetchPlayers(
          doc,
          "div.row:nth-child(9) > div:nth-child(2) > div:nth-child(1) > div:nth-child(2) > table:nth-child(1)",
          false,
          true,
        );
        resolve();
      },
    });
  });
}

async function generateMatchCourseData() {
  subEvents.length = 0;
  goalEvents.length = 0;
  return new Promise((resolve) => {
    generateGoalsData();
    generateSubData();
    generateCardData();
    resolve();
  });
}

function generateGoalsData() {
  goalEvents.length = 0;
  const container = document.querySelector("#sb-tore");
  if (!container) return;

  const actions = Array.from(container.querySelectorAll("li"));
  actions.forEach((action) => {
    const baseData = getActionBaseData(action);
    const players = action.querySelectorAll("a.wichtig");
    const player = players[0].href;
    const assist = players[1]?.href ?? null;

    goalEvents.push({
      ...baseData,
      player,
      assist,
    });
  });
}

function generateSubData() {
  subEvents.length = 0;
  const container = document.querySelector("#sb-wechsel");
  if (!container) return;

  const actions = Array.from(container.querySelectorAll("li"));
  actions.forEach((action) => {
    const baseData = getActionBaseData(action);
    const on = action.querySelector(".sb-aktion-wechsel-ein .wichtig").href;
    const off = action.querySelector(".sb-aktion-wechsel-aus .wichtig").href;

    subEvents.push({
      ...baseData,
      on,
      off,
    });
  });
}

function generateCardData() {
  cardEvents.length = 0;
  const container = document.querySelector("#sb-karten");
  if (!container) return;

  const actions = Array.from(container.querySelectorAll("li"));
  actions.forEach((action) => {
    const baseData = getActionBaseData(action);
    const id = action.querySelector(".sb-aktion-aktion .wichtig").href;

    let type;
    if (action.querySelector(".sb-gelb")) type = "yellow";
    else if (action.querySelector(".sb-gelbrot")) type = "yellow-red";
    else if (action.querySelector(".sb-rot")) type = "red";

    cardEvents.push({
      ...baseData,
      id,
      card: type,
    });
  });
}

function getActionBaseData(action) {
  const home = !action.classList.contains("sb-aktion-gast");
  const clockPos = action
    .querySelector(".sb-sprite-uhr-klein")
    .style.backgroundPosition.split(" ")
    .map((c) => c.split("px")[0]);
  const minute = getTime(clockPos[0], clockPos[1]).toString();
  let added =
    action.querySelector(".sb-sprite-uhr-klein").innerText.trim() ?? null;
  if (added.length === 0) added = null;
  else added = added.substring(1);

  return {
    home,
    minute,
    added,
  };
}

function getTime(x, y) {
  x = parseInt(x);
  y = parseInt(y);
  const spriteWidth = 36;
  const spriteHeight = 36;
  const columns = 10;

  let col = Math.abs(x) / spriteWidth;
  let row = Math.abs(y) / spriteHeight;

  return row * columns + col + 1;
}

async function delay(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

GM_addStyle(`
#floatingButton {
position: fixed;
bottom: 20px;
right: 20px;
padding: 10px 20px;
background-color: #007BFF;
color: white;
font-size: 16px;
font-weight: bold;
border: none;
border-radius: 10px;
box-shadow: 2px 2px 10px rgba(0, 0, 0, 0.2);
cursor: pointer;
z-index: 9999;
transition: background-color 0.3s ease, transform 0.2s ease;
}
#floatingButton:hover {
background-color: #0056b3;
transform: scale(1.1);
}
`);

document.body.appendChild(btn);

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址