From 55c12ceedcd3b4800e9323c72f2b95eddb899373 Mon Sep 17 00:00:00 2001 From: 230421 <230421@epvc.pt> Date: Wed, 11 Mar 2026 09:47:26 +0000 Subject: [PATCH] tabela de classificacoes --- .../java/org/example/StandingsScraper.java | 193 +++++++++++++++++ .../java/org/example/models/TeamStanding.java | 202 ++++++++++++++++++ 2 files changed, 395 insertions(+) create mode 100644 src/main/java/org/example/StandingsScraper.java create mode 100644 src/main/java/org/example/models/TeamStanding.java diff --git a/src/main/java/org/example/StandingsScraper.java b/src/main/java/org/example/StandingsScraper.java new file mode 100644 index 0000000..fc0b99c --- /dev/null +++ b/src/main/java/org/example/StandingsScraper.java @@ -0,0 +1,193 @@ +package org.example; + +import com.google.auth.oauth2.GoogleCredentials; +import com.google.firebase.FirebaseApp; +import com.google.firebase.FirebaseOptions; +import com.google.firebase.database.DatabaseReference; +import com.google.firebase.database.FirebaseDatabase; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import org.example.models.Club; +import org.example.models.TeamStanding; +import org.jsoup.Connection; +import org.jsoup.Jsoup; + +import java.io.FileInputStream; +import java.util.*; + +public class StandingsScraper { + public static void main(String[] args) { + + String caminhoChave = "service-account.json"; + String urlDatabase = "https://vdcscore-default-rtdb.firebaseio.com/"; + + try { + System.out.println("--- A CONECTAR AO FIREBASE ---"); + if (FirebaseApp.getApps().isEmpty()) { + FileInputStream serviceAccount = new FileInputStream(caminhoChave); + FirebaseOptions options = FirebaseOptions.builder() + .setCredentials(GoogleCredentials.fromStream(serviceAccount)) + .setDatabaseUrl(urlDatabase) + .build(); + FirebaseApp.initializeApp(options); + } + } catch (Exception e) { + System.err.println("ERRO FIREBASE: Verifica o service-account.json!"); + e.printStackTrace(); + return; + } + + Gson gson = new Gson(); + Map clubesMap = new HashMap<>(); + + // 1. Obter todos os Clubes e seus meta-dados + System.out.println("\n--- A EXTRAIR DADOS DOS CLUBES ---"); + try { + String urlTodosClubes = "https://api.afavcd.pt/teams"; + String jsonTodosClubes = Jsoup.connect(urlTodosClubes) + .ignoreContentType(true) + .userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64)") + .header("Referer", "https://www.afavcd.pt/") + .header("Origin", "https://www.afavcd.pt") + .method(Connection.Method.GET) + .execute() + .body(); + + List> dadosClubes = gson.fromJson(jsonTodosClubes, + new TypeToken>>() { + }.getType()); + + for (Map c : dadosClubes) { + if (c.get("teamID") != null) { + int clubId = (int) Double.parseDouble(c.get("teamID").toString()); + Club club = new Club(); + club.setId(clubId); + if (c.get("name") != null) + club.setName(c.get("name").toString()); + if (c.get("logoURL") != null) + club.setImageUrl(c.get("logoURL").toString()); + + clubesMap.put(clubId, club); + } + } + System.out.println("Encontrados " + clubesMap.size() + " clubes."); + } catch (Exception e) { + System.err.println("Erro ao obter lista de clubes."); + e.printStackTrace(); + return; + } + + int[] modalidades = { 3, 1 }; + String[] nomesEscaloes = { "juniores", "seniores" }; + + for (int i = 0; i < modalidades.length; i++) { + int modalidade = modalidades[i]; + String escalao = nomesEscaloes[i]; + + System.out.println("\n========================================"); + System.out.println("A CALCULAR CLASSIFICAÇÃO PARA: " + escalao.toUpperCase()); + System.out.println("========================================"); + + String urlJornadas = "https://api.afavcd.pt/seasons/33/teams/modality/" + modalidade + "/jorneys"; + try { + String jsonJornadas = Jsoup.connect(urlJornadas) + .ignoreContentType(true) + .userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64)") + .header("Referer", "https://www.afavcd.pt/") + .header("Origin", "https://www.afavcd.pt") + .method(Connection.Method.GET) + .execute() + .body(); + + Map>> matchdays = gson.fromJson(jsonJornadas, + new TypeToken>>>() { + }.getType()); + + Map standingsMap = new HashMap<>(); + + for (List> matchday : matchdays.values()) { + for (Map match : matchday) { + try { + int homeTeamId = parseId(match.get("Home")); + int awayTeamId = parseId(match.get("Away")); + + // Ignorar jogos com equipas placeholder / de descanso + if (homeTeamId < 0 || awayTeamId < 0) + continue; + + String homeGoalsStr = String.valueOf(match.get("homeGoals")); + String awayGoalsStr = String.valueOf(match.get("awayGoals")); + + if (homeGoalsStr != null && !homeGoalsStr.trim().isEmpty() + && !homeGoalsStr.equals("null")) { + int homeGoals = (int) Double.parseDouble(homeGoalsStr); + int awayGoals = (int) Double.parseDouble(awayGoalsStr); + + // Inicializar as equipas caso não existam no standingsMap + standingsMap.putIfAbsent(homeTeamId, createInitialStanding(homeTeamId, clubesMap)); + standingsMap.putIfAbsent(awayTeamId, createInitialStanding(awayTeamId, clubesMap)); + + standingsMap.get(homeTeamId).addMatchResult(homeGoals, awayGoals); + standingsMap.get(awayTeamId).addMatchResult(awayGoals, homeGoals); + } + } catch (Exception ex) { + // Ignorar erro em um jogo específico (dados incorretos, etc) + } + } + } + + // Transformar em lista e ordenar + List sortedStandings = new ArrayList<>(standingsMap.values()); + Collections.sort(sortedStandings); + + System.out.println("Classificação Final " + escalao.toUpperCase() + ":"); + int posicao = 1; + for (TeamStanding ts : sortedStandings) { + ts.setPosition(posicao); + System.out.printf("%d. %s - %d pts (J:%d, V:%d, E:%d, D:%d, GM:%d, GS:%d)\n", + posicao, ts.getName(), ts.getPoints(), ts.getMatchesPlayed(), ts.getWins(), ts.getDraws(), + ts.getLosses(), ts.getGoalsFor(), ts.getGoalsAgainst()); + posicao++; + } + + // Enviar para Firebase + DatabaseReference refClassificacoes = FirebaseDatabase.getInstance() + .getReference("classificacoes").child(escalao); + + refClassificacoes.setValueAsync(sortedStandings); + System.out.println("-> Classificação de " + escalao + " enviada para o Firebase."); + + } catch (Exception e) { + System.err.println("Erro a processar " + escalao); + e.printStackTrace(); + } + } + + try { + System.out.println("\nAguardando confirmação do servidor (5s)..."); + Thread.sleep(5000); + System.out.println("Processo concluído!"); + System.exit(0); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + private static int parseId(Object value) { + if (value == null) + return -1; + try { + return (int) Double.parseDouble(value.toString()); + } catch (NumberFormatException e) { + return -1; + } + } + + private static TeamStanding createInitialStanding(int teamId, Map clubesMap) { + Club club = clubesMap.get(teamId); + if (club != null) { + return new TeamStanding(teamId, club.getName(), club.getImageUrl()); + } + return new TeamStanding(teamId, "Equipa " + teamId, ""); + } +} diff --git a/src/main/java/org/example/models/TeamStanding.java b/src/main/java/org/example/models/TeamStanding.java new file mode 100644 index 0000000..88a1b3e --- /dev/null +++ b/src/main/java/org/example/models/TeamStanding.java @@ -0,0 +1,202 @@ +package org.example.models; + +import com.google.firebase.database.PropertyName; + +public class TeamStanding implements Comparable { + + @PropertyName("team_id") + private int teamId; + + @PropertyName("nome") + private String name; + + @PropertyName("imagem") + private String imageUrl; + + @PropertyName("posicao") + private int position; + + @PropertyName("pontos") + private int points; + + @PropertyName("jogos") + private int matchesPlayed; + + @PropertyName("vitorias") + private int wins; + + @PropertyName("empates") + private int draws; + + @PropertyName("derrotas") + private int losses; + + @PropertyName("golos_marcados") + private int goalsFor; + + @PropertyName("golos_sofridos") + private int goalsAgainst; + + @PropertyName("diferenca_golos") + private int goalDifference; + + public TeamStanding() { + } + + public TeamStanding(int teamId, String name, String imageUrl) { + this.teamId = teamId; + this.name = name; + this.imageUrl = imageUrl; + } + + public void addMatchResult(int goalsScored, int goalsConceded) { + this.matchesPlayed++; + this.goalsFor += goalsScored; + this.goalsAgainst += goalsConceded; + this.goalDifference = this.goalsFor - this.goalsAgainst; + + if (goalsScored > goalsConceded) { + this.wins++; + this.points += 3; + } else if (goalsScored == goalsConceded) { + this.draws++; + this.points += 1; + } else { + this.losses++; + } + } + + @Override + public int compareTo(TeamStanding other) { + if (this.points != other.points) { + return Integer.compare(other.points, this.points); + } + if (this.goalDifference != other.goalDifference) { + return Integer.compare(other.goalDifference, this.goalDifference); + } + if (this.goalsFor != other.goalsFor) { + return Integer.compare(other.goalsFor, this.goalsFor); + } + return this.name.compareToIgnoreCase(other.name); + } + + @PropertyName("team_id") + public int getTeamId() { + return teamId; + } + + @PropertyName("team_id") + public void setTeamId(int teamId) { + this.teamId = teamId; + } + + @PropertyName("nome") + public String getName() { + return name; + } + + @PropertyName("nome") + public void setName(String name) { + this.name = name; + } + + @PropertyName("imagem") + public String getImageUrl() { + return imageUrl; + } + + @PropertyName("imagem") + public void setImageUrl(String imageUrl) { + this.imageUrl = imageUrl; + } + + @PropertyName("posicao") + public int getPosition() { + return position; + } + + @PropertyName("posicao") + public void setPosition(int position) { + this.position = position; + } + + @PropertyName("pontos") + public int getPoints() { + return points; + } + + @PropertyName("pontos") + public void setPoints(int points) { + this.points = points; + } + + @PropertyName("jogos") + public int getMatchesPlayed() { + return matchesPlayed; + } + + @PropertyName("jogos") + public void setMatchesPlayed(int matchesPlayed) { + this.matchesPlayed = matchesPlayed; + } + + @PropertyName("vitorias") + public int getWins() { + return wins; + } + + @PropertyName("vitorias") + public void setWins(int wins) { + this.wins = wins; + } + + @PropertyName("empates") + public int getDraws() { + return draws; + } + + @PropertyName("empates") + public void setDraws(int draws) { + this.draws = draws; + } + + @PropertyName("derrotas") + public int getLosses() { + return losses; + } + + @PropertyName("derrotas") + public void setLosses(int losses) { + this.losses = losses; + } + + @PropertyName("golos_marcados") + public int getGoalsFor() { + return goalsFor; + } + + @PropertyName("golos_marcados") + public void setGoalsFor(int goalsFor) { + this.goalsFor = goalsFor; + } + + @PropertyName("golos_sofridos") + public int getGoalsAgainst() { + return goalsAgainst; + } + + @PropertyName("golos_sofridos") + public void setGoalsAgainst(int goalsAgainst) { + this.goalsAgainst = goalsAgainst; + } + + @PropertyName("diferenca_golos") + public int getGoalDifference() { + return goalDifference; + } + + @PropertyName("diferenca_golos") + public void setGoalDifference(int goalDifference) { + this.goalDifference = goalDifference; + } +}