diff --git a/src/main/java/com/appdev/allin/Application.java b/src/main/java/com/appdev/allin/Application.java index d982e3c..8cacbd3 100644 --- a/src/main/java/com/appdev/allin/Application.java +++ b/src/main/java/com/appdev/allin/Application.java @@ -21,6 +21,8 @@ import org.springframework.scheduling.annotation.Scheduled; +import com.appdev.allin.playerData.PlayerData; + @SpringBootApplication @EnableScheduling public class Application { @@ -67,9 +69,33 @@ public void checkAndProcessContracts() { } } - // TODO: Finish public boolean isContractHit(Contract contract) { - return true; + + if (contract == null || contract.getPlayer() == null || contract.getEvent() == null || contract.getOpposingTeam() == null) { + return false; + } + if (contract.getExpired() != null && contract.getExpired()) { + return false; + } + + // getting player data + List playerDataList = playerDataRepo.findByPlayer(contract.getPlayer()); + + // no data found, so contract is not hit + if (playerDataList == null || playerDataList.isEmpty()) { + return false; + } + // comparing data to contract + for (PlayerData playerData : playerDataList) { + if (playerData.getOpposingTeam() == contract.getOpposingTeam()) { + Integer actualValue = playerData.getEvent(contract.getEvent()); + if (actualValue >= contract.getEventThreshold()) { + return true; + } + } + } + return false; + } private void processPayout(Contract contract) { diff --git a/src/main/java/com/appdev/allin/DataInitializer.java b/src/main/java/com/appdev/allin/DataInitializer.java index 9165440..79b0fd5 100644 --- a/src/main/java/com/appdev/allin/DataInitializer.java +++ b/src/main/java/com/appdev/allin/DataInitializer.java @@ -1,63 +1,84 @@ package com.appdev.allin; -import com.appdev.allin.player.PlayerRepo; -import com.appdev.allin.playerData.PlayerDataRepo; -import com.appdev.allin.gameData.GameDataRepo; - -import com.appdev.allin.scrapers.PlayerScraper; -import com.appdev.allin.scrapers.PlayerDataScraper; -import com.appdev.allin.scrapers.GameDataScraper; - -// import java.util.concurrent.Executors; -// import java.util.concurrent.ScheduledExecutorService; -// import java.util.concurrent.TimeUnit; +import java.text.NumberFormat; import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; +import com.appdev.allin.gameData.GameDataService; +import com.appdev.allin.player.PlayerService; +import com.appdev.allin.playerData.PlayerDataService; +import com.appdev.allin.scrapers.GameDataScraper; +import com.appdev.allin.scrapers.PlayerDataScraper; +import com.appdev.allin.scrapers.PlayerScraper; + @Component public class DataInitializer { - private final PlayerRepo playerRepo; - private final PlayerDataRepo playerDataRepo; - private final GameDataRepo gameDataRepo; + private final PlayerService playerService; + private final PlayerDataService playerDataService; + private final GameDataService gameDataService; - public DataInitializer(PlayerRepo playerRepo, PlayerDataRepo playerDataRepo, GameDataRepo gameDataRepo) { - this.playerRepo = playerRepo; - this.playerDataRepo = playerDataRepo; - this.gameDataRepo = gameDataRepo; + public DataInitializer(PlayerService playerService, PlayerDataService playerDataService, GameDataService gameDataService) { + this.playerService = playerService; + this.playerDataService = playerDataService; + this.gameDataService = gameDataService; } @EventListener(ApplicationReadyEvent.class) public void initializeData() { - // PlayerScraper playerScraper = new PlayerScraper(playerRepo); - // playerScraper.run(); + logMemoryUsage("Before player scraper"); + PlayerScraper playerScraper = new PlayerScraper(playerService); + playerScraper.run(); + + logMemoryUsage("After player scraper"); + + PlayerDataScraper playerDataScraper = new PlayerDataScraper(playerService, + playerDataService); + playerDataScraper.run(); + + logMemoryUsage("After player data scraper"); - // PlayerDataScraper playerDataScraper = new PlayerDataScraper(playerRepo, - // playerDataRepo); - // playerDataScraper.run(); + GameDataScraper gameDataScraper = new GameDataScraper(gameDataService); + gameDataScraper.run(); + logMemoryUsage("After all scrapers"); - // GameDataScraper gameDataScraper = new GameDataScraper(gameDataRepo); - // gameDataScraper.run(); - // Uncomment the above lines to schedule the scrapers to run periodically + // Uncoment the above lines to schedule the scrapers to run periodically // ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); // scheduler.scheduleAtFixedRate(() -> { // try { - // PlayerScraper playerScraper = new PlayerScraper(playerRepo); - // playerScraper.run(); + // PlayerScraper playerScraper = new PlayerScraper(playerService); + // playerScraper.run(); - // PlayerDataScraper playerDataScraper = new PlayerDataScraper(playerRepo, - // playerDataRepo); - // playerDataScraper.run(); + // PlayerDataScraper playerDataScraper = new PlayerDataScraper(playerService, + // playerDataService); + // playerDataScraper.run(); - // GameDataScraper gameDataScraper = new GameDataScraper(gameDataRepo); - // gameDataScraper.run(); + // GameDataScraper gameDataScraper = new GameDataScraper(gameDataService); + // gameDataScraper.run(); // } catch (Exception e) { // e.printStackTrace(); // } // }, 0, 1, TimeUnit.DAYS); // Initial delay: 0, Repeat every 1 day } + + + private void logMemoryUsage(String point) { + Runtime runtime = Runtime.getRuntime(); + NumberFormat format = NumberFormat.getInstance(); + + long maxMemory = runtime.maxMemory(); + long allocatedMemory = runtime.totalMemory(); + long freeMemory = runtime.freeMemory(); + long usedMemory = allocatedMemory - freeMemory; + + System.out.println("Memory Usage at " + point); + System.out.println("Max Memory: " + format.format(maxMemory / 1024 / 1024) + " MB"); + System.out.println("Allocated Memory: " + format.format(allocatedMemory / 1024 / 1024) + " MB"); + System.out.println("Used Memory: " + format.format(usedMemory / 1024 / 1024) + " MB"); + System.out.println("Free Memory: " + format.format(freeMemory / 1024 / 1024) + " MB"); + } } diff --git a/src/main/java/com/appdev/allin/SecurityConfig.java b/src/main/java/com/appdev/allin/SecurityConfig.java index 15a9683..ac3d0d1 100644 --- a/src/main/java/com/appdev/allin/SecurityConfig.java +++ b/src/main/java/com/appdev/allin/SecurityConfig.java @@ -25,7 +25,8 @@ SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { "/swagger-ui/**", "/v3/api-docs/**", "/swagger-resources/**", - "/webjars/**") + "/webjars/**" + ) .permitAll() .anyRequest().authenticated()) // Needed for Spring to place the filter in the correct order diff --git a/src/main/java/com/appdev/allin/gameData/GameDataService.java b/src/main/java/com/appdev/allin/gameData/GameDataService.java new file mode 100644 index 0000000..7c9a02d --- /dev/null +++ b/src/main/java/com/appdev/allin/gameData/GameDataService.java @@ -0,0 +1,19 @@ +package com.appdev.allin.gameData; +import org.springframework.stereotype.Service; + +@Service +public class GameDataService { + private final GameDataRepo gameDataRepo; + + public GameDataService(GameDataRepo gameDataRepo) { + this.gameDataRepo = gameDataRepo; + } + + public GameData findByOpposingTeamAndGameDateTime(String opposingTeam, String gameDateTime) { + return gameDataRepo.findByOpposingTeamAndGameDateTime(opposingTeam, gameDateTime); + } + + public GameData saveGameData(GameData gameData) { + return gameDataRepo.save(gameData); + } +} diff --git a/src/main/java/com/appdev/allin/player/PlayerService.java b/src/main/java/com/appdev/allin/player/PlayerService.java index 3f970a3..30b089b 100644 --- a/src/main/java/com/appdev/allin/player/PlayerService.java +++ b/src/main/java/com/appdev/allin/player/PlayerService.java @@ -1,8 +1,15 @@ package com.appdev.allin.player; -import com.appdev.allin.exceptions.NotFoundException; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.List; +import java.util.Optional; + import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import com.appdev.allin.exceptions.NotFoundException; +import com.appdev.allin.utils.Constants; @Service public class PlayerService { @@ -23,7 +30,118 @@ public Player getPlayerById(final Integer pid) { return player; } + public Player getPlayerByNumber(final Integer number) { + Player player = playerRepo.findByNumber(number); + return player; + } + + public Player savePlayer(final Player player) { + Player existingPlayer = playerRepo.findByFirstNameAndLastName(player.getFirstName(), + player.getLastName()); + if (existingPlayer == null) { + return playerRepo.save(player); + } + return existingPlayer; + } + + public Player createPlayer(final Player player) { return playerRepo.save(player); } -} + + public Player updatePlayer(final Integer player_id, final Player player) + throws NotFoundException { + Optional playerOptional = playerRepo.findById(player_id); + if (playerOptional.isEmpty()) { + throw new NotFoundException("Player with id " + player_id + " not found."); + } + Player playerToUpdate = playerOptional.get(); + playerToUpdate.setFirstName(player.getFirstName()); + playerToUpdate.setLastName(player.getLastName()); + playerToUpdate.setPositions(player.getPositions()); + playerToUpdate.setNumber(player.getNumber()); + playerToUpdate.setHeight(player.getHeight()); + playerToUpdate.setWeight(player.getWeight()); + playerToUpdate.setHometown(player.getHometown()); + playerToUpdate.setHighSchool(player.getHighSchool()); + playerToUpdate.setImage(player.getImage()); + return playerRepo.save(playerToUpdate); + } + + public Player deletePlayer(final Integer player_id) throws NotFoundException { + Optional playerOptional = playerRepo.findById(player_id); + if (playerOptional.isEmpty()) { + throw new NotFoundException("Player with id " + player_id + " not found."); + } + playerRepo.deleteById(player_id); + return playerOptional.get(); + } + + public byte[] getImageFromStorage(final String uploadDirectory, final String fileName) { + Path uploadPath = Path.of(uploadDirectory); + Path filePath = uploadPath.resolve(fileName); + try { + return Files.readAllBytes(filePath); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public void updatePlayerImageById( + final Integer player_id, final MultipartFile image, final String uploadDirectory) + throws NotFoundException { + Optional playerOptional = playerRepo.findById(player_id); + if (playerOptional.isEmpty()) { + throw new NotFoundException("Player with id " + player_id + " not found."); + } + Player playerToUpdate = playerOptional.get(); + String uniqueFileName = player_id + "_" + image.getOriginalFilename(); + Path uploadPath = Path.of(uploadDirectory); + Path filePath = uploadPath.resolve(uniqueFileName); + if (!Files.exists(uploadPath)) { + try { + Files.createDirectories(uploadPath); + } catch (Exception e) { + e.printStackTrace(); + } + } + try { + Files.copy( + image.getInputStream(), filePath, java.nio.file.StandardCopyOption.REPLACE_EXISTING); + } catch (Exception e) { + e.printStackTrace(); + } + playerToUpdate.setImage(uploadDirectory + uniqueFileName); + playerRepo.save(playerToUpdate); + } + + public boolean deletePlayerImageById(final Integer player_id, final String uploadDirectory) + throws NotFoundException { + Optional playerOptional = playerRepo.findById(player_id); + if (playerOptional.isEmpty()) { + throw new NotFoundException("Player with id " + player_id + " not found."); + } + Player playerToUpdate = playerOptional.get(); + String image = playerToUpdate.getImage(); + if (image.equals(Constants.DEFAULT_PLAYER_IMAGE)) { + return false; + } + Path pathToFile = Path.of(playerToUpdate.getImage()); + try { + Files.delete(pathToFile); + playerToUpdate.setImage("src/main/resources/static/images/players/default.jpg"); + playerRepo.save(playerToUpdate); + return true; + } catch (Exception e) { + e.printStackTrace(); + } + return false; + } + + public Player getPlayerByFirstNameAndLastName(final String firstName, + final String lastName) { + Player player = playerRepo.findByFirstNameAndLastName(firstName, lastName); + return player; + } +} \ No newline at end of file diff --git a/src/main/java/com/appdev/allin/playerData/PlayerDataService.java b/src/main/java/com/appdev/allin/playerData/PlayerDataService.java index 1f0b025..1466bd3 100644 --- a/src/main/java/com/appdev/allin/playerData/PlayerDataService.java +++ b/src/main/java/com/appdev/allin/playerData/PlayerDataService.java @@ -28,4 +28,8 @@ public List getPlayerDataByPlayer(final Player player) { public List getPlayerDataByDate(final LocalDate gameDate) { return playerDataRepo.findByGameDate(gameDate); } + + public List getPlayerDataByDateAndPlayer(Player player, LocalDate gameDate) { + return playerDataRepo.findByPlayerAndGameDate(player, gameDate); +} } diff --git a/src/main/java/com/appdev/allin/scrapers/GameDataScraper.java b/src/main/java/com/appdev/allin/scrapers/GameDataScraper.java index 3c62d8c..d48cea0 100644 --- a/src/main/java/com/appdev/allin/scrapers/GameDataScraper.java +++ b/src/main/java/com/appdev/allin/scrapers/GameDataScraper.java @@ -11,23 +11,23 @@ import org.slf4j.LoggerFactory; import com.appdev.allin.gameData.GameData; -import com.appdev.allin.gameData.GameDataRepo; +import com.appdev.allin.gameData.GameDataService; public class GameDataScraper { private static final Logger logger = LoggerFactory.getLogger(GameDataScraper.class); - private final GameDataRepo gameDataRepo; + private final GameDataService gameDataService; - public GameDataScraper(GameDataRepo gameDataRepo) { - this.gameDataRepo = Objects.requireNonNull(gameDataRepo); + public GameDataScraper(GameDataService gameDataService) { + this.gameDataService = Objects.requireNonNull(gameDataService); } - private static final String SCHEDULE_URL = "https://cornellbigred.com/sports/mens-basketball/schedule/2024-25"; + private static final String BASE_URL = "https://cornellbigred.com/sports/mens-basketball/schedule/2024-25"; - public void populateUpcomingGames() throws IOException { - logger.info("Scraping game schedule data from URL: {}", SCHEDULE_URL); + public void populate() throws IOException { + logger.info("Scraping game schedule data from URL: {}", BASE_URL); try { - Document doc = Jsoup.connect(SCHEDULE_URL).get(); + Document doc = Jsoup.connect(BASE_URL).get(); Elements gameElements = doc.select("div.sidearm-schedule-game-opponent-name"); Elements dateElements = doc.select("div.sidearm-schedule-game-opponent-date"); @@ -63,11 +63,12 @@ public void populateUpcomingGames() throws IOException { logger.info("Upcoming Game {}: {} on {} in {}, Logo URL: {}", i + 1, opponentName, gameDate, fullLocation, logoUrl); GameData gameData = new GameData(opponentName, gameDate, fullLocation, logoUrl); - if (gameDataRepo.findByOpposingTeamAndGameDateTime(opponentName, gameDate) == null) { - gameDataRepo.save(gameData); + if (gameDataService.findByOpposingTeamAndGameDateTime(opponentName, gameDate) == null) { + gameDataService.saveGameData(gameData); } else { logger.info("Game {} with opponent: {} already exists in the database", i + 1, opponentName); } + System.gc(); } logger.info("Game schedule scraping completed"); @@ -80,7 +81,7 @@ public void populateUpcomingGames() throws IOException { public void run() { try { - populateUpcomingGames(); + populate(); } catch (IOException e) { logger.error("Failed to populate game schedule data: {}", e.getMessage()); } diff --git a/src/main/java/com/appdev/allin/scrapers/PlayerDataScraper.java b/src/main/java/com/appdev/allin/scrapers/PlayerDataScraper.java index 755949f..0191ea5 100644 --- a/src/main/java/com/appdev/allin/scrapers/PlayerDataScraper.java +++ b/src/main/java/com/appdev/allin/scrapers/PlayerDataScraper.java @@ -1,10 +1,13 @@ package com.appdev.allin.scrapers; -import com.appdev.allin.player.Player; -import com.appdev.allin.player.PlayerRepo; -import com.appdev.allin.playerData.PlayerData; -import com.appdev.allin.playerData.PlayerDataRepo; -import com.appdev.allin.contract.OpposingTeam; +import java.io.IOException; +import java.time.LocalDate; +import java.time.Year; +import java.time.format.DateTimeFormatter; +import java.util.HashSet; +import java.util.Set; +import java.util.List; +import com.appdev.allin.exceptions.NotFoundException; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; @@ -14,20 +17,18 @@ import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; -import java.io.IOException; -import java.time.LocalDate; -import java.time.Year; -import java.time.format.DateTimeFormatter; -import java.util.HashSet; -import java.util.Set; -import java.util.TreeSet; +import com.appdev.allin.contract.OpposingTeam; +import com.appdev.allin.player.Player; +import com.appdev.allin.player.PlayerService; +import com.appdev.allin.playerData.PlayerData; +import com.appdev.allin.playerData.PlayerDataService; @Component public class PlayerDataScraper { private static final Logger logger = LoggerFactory.getLogger(PlayerDataScraper.class); - private final PlayerRepo playerRepo; - private final PlayerDataRepo playerDataRepo; + private final PlayerService playerService; + private final PlayerDataService playerDataService; private static final String BASE_URL = "https://cornellbigred.com"; private static final DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("MM/dd/yy"); private static final String USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"; @@ -36,16 +37,16 @@ public class PlayerDataScraper { private final Set processedGameUrls = new HashSet<>(); // Set to track unmatched teams - private final Set unmatchedTeams = new TreeSet<>(); // TreeSet for sorted output + private final Set unmatchedTeams = new HashSet<>(); - public PlayerDataScraper(PlayerRepo playerRepo, PlayerDataRepo playerDataRepo) { - this.playerRepo = playerRepo; - this.playerDataRepo = playerDataRepo; + public PlayerDataScraper(PlayerService playerService, PlayerDataService playerDataService) { + this.playerService = playerService; + this.playerDataService = playerDataService; } public void populate() throws IOException { - int startYear = Year.now().getValue() - 4; int endYear = Year.now().getValue(); + int startYear = endYear - 4; for (int year = startYear; year <= endYear; year++) { // Format: 2023-24 @@ -86,9 +87,10 @@ public void scrapeGameStats(String scheduleUrl) throws IOException { .userAgent(USER_AGENT) .get(); processGameStats(gameDoc); - } catch (Exception e) { + } catch (IOException e) { logger.error("Error scraping individual game {}: {}", gameUrl, e.getMessage()); } + System.gc(); } } catch (IOException e) { logger.error("Error scraping schedule from URL {}: {}", scheduleUrl, e.getMessage()); @@ -145,7 +147,8 @@ private void processGameStats(Document gameDoc) throws IOException { } // Check if stats already exist for this player and game - if (playerDataRepo.findByPlayerAndGameDate(player, gameDate).isEmpty()) { + List existingStats = playerDataService.getPlayerDataByDateAndPlayer(player, gameDate); + if (existingStats.isEmpty()) { PlayerData gameStats = new PlayerData(); gameStats.setPlayer(player); gameStats.setGameDate(gameDate); @@ -164,7 +167,7 @@ private void processGameStats(Document gameDoc) throws IOException { gameStats.setTurnovers(parseIntStat(row, "TO")); gameStats.setFouls(parseIntStat(row, "PF")); - PlayerData saved = playerDataRepo.saveAndFlush(gameStats); + PlayerData saved = playerDataService.createPlayerData(gameStats); logger.info("Saved stats for player {} with ID {}", playerName, saved.getId()); savedCount++; } else { @@ -227,23 +230,53 @@ private OpposingTeam findOpposingTeam(String scrapedTeamName) { } Player findPlayerByName(String fullName) { - String[] nameParts = fullName.split(",", 2); - if (nameParts.length != 2) { - logger.warn("Invalid name format: {}", fullName); + try { + // Check if format is "Last, First" + if (fullName.contains(",")) { + String[] nameParts = fullName.split(",", 2); + String lastName = nameParts[0].trim(); + String firstName = nameParts[1].trim(); + + logger.debug("Looking up player: firstName='{}', lastName='{}'", firstName, lastName); + try { + return playerService.getPlayerByFirstNameAndLastName(firstName, lastName); + } catch (NotFoundException e) { + logger.warn("Player not found: {}", fullName); + } + } + // Format is "First Last" + else { + String[] nameParts = fullName.split(" "); + if (nameParts.length >= 2) { + String firstName = nameParts[0].trim(); + // Last name might be multiple words (e.g., "Ragland Jr.") + StringBuilder lastName = new StringBuilder(); + for (int i = 1; i < nameParts.length; i++) { + if (i > 1) lastName.append(" "); + lastName.append(nameParts[i]); + } + + logger.debug("Looking up player by First Last format: firstName='{}', lastName='{}'", + firstName, lastName.toString()); + try { + return playerService.getPlayerByFirstNameAndLastName(firstName, lastName.toString()); + } catch (NotFoundException e) { + logger.warn("Player not found: {}", fullName); + } + } + } + + return null; + } catch (Exception e) { + logger.warn("Error parsing player name: {}", fullName); return null; } - - String lastName = nameParts[0].trim(); - String firstName = nameParts[1].trim(); - - logger.debug("Looking up player: firstName='{}', lastName='{}'", firstName, lastName); - return playerRepo.findByFirstNameAndLastName(firstName, lastName); } public void run() { try { populate(); - long count = playerDataRepo.count(); + long count = playerDataService.getAllPlayerData().size(); logger.info("Total player data records after scraping: {}", count); } catch (IOException e) { logger.error("Failed to populate player stats: {}", e.getMessage()); diff --git a/src/main/java/com/appdev/allin/scrapers/PlayerScraper.java b/src/main/java/com/appdev/allin/scrapers/PlayerScraper.java index 0be6b0d..8c60e71 100644 --- a/src/main/java/com/appdev/allin/scrapers/PlayerScraper.java +++ b/src/main/java/com/appdev/allin/scrapers/PlayerScraper.java @@ -12,24 +12,24 @@ import org.slf4j.LoggerFactory; import com.appdev.allin.player.Player; -import com.appdev.allin.player.PlayerRepo; +import com.appdev.allin.player.PlayerService; import com.appdev.allin.player.Position; public class PlayerScraper { private static final Logger logger = LoggerFactory.getLogger(PlayerScraper.class); - private final PlayerRepo playerRepo; + private final PlayerService playerService; - private static final String ROSTER_URL = "https://cornellbigred.com/sports/mens-basketball/roster?view=2"; + private static final String BASE_URL = "https://cornellbigred.com/sports/mens-basketball/roster?view=2"; - public PlayerScraper(PlayerRepo playerRepo) { - this.playerRepo = playerRepo; + public PlayerScraper(PlayerService playerService) { + this.playerService = playerService; } public void populate() throws IOException { - logger.info("Scraping player data from URL: {}", ROSTER_URL); + logger.info("Scraping player data from URL: {}", BASE_URL); try { - Document doc = Jsoup.connect(ROSTER_URL).get(); + Document doc = Jsoup.connect(BASE_URL).get(); Elements playerElements = doc.select("ul.sidearm-roster-players > li.sidearm-roster-player"); @@ -61,14 +61,14 @@ public void populate() throws IOException { String highSchool = extractText(playerElement, "span.sidearm-roster-player-highschool"); Element imageElement = playerElement.selectFirst("div.sidearm-roster-player-image img"); - String imageUrl = imageElement != null ? imageElement.attr("data-src") : ""; + String imageUrl = imageElement != null ? "https://cornellbigred.com" + imageElement.attr("data-src") : ""; if (number == null || firstName.isEmpty() || lastName.isEmpty()) { logger.warn("Bad data for player {} {}", firstName, lastName); continue; } - Player existingPlayer = playerRepo.findByNumber(number); + Player existingPlayer = playerService.getPlayerByNumber(number); if (existingPlayer != null) { logger.warn("Player already exists."); continue; @@ -77,12 +77,13 @@ public void populate() throws IOException { Player player = new Player(firstName, lastName, positions, number, height, weight, hometown, highSchool, imageUrl); - if (playerRepo.findByNumber(player.getNumber()) == null) { - playerRepo.save(player); + if (playerService.getPlayerByNumber(player.getNumber()) == null) { + playerService.savePlayer(player); logger.info("Saved player: {} {}", firstName, lastName); } else { logger.warn("Player already exists: {}", player); } + System.gc(); } logger.info("Player data scraping completed"); @@ -109,7 +110,7 @@ private String extractText(Element element, String cssQuery) { private Integer extractIntegerFromString(String text) { try { - return Integer.parseInt(text.replaceAll("[^\\d]", "")); + return Integer.valueOf(text.replaceAll("[^\\d]", "")); } catch (NumberFormatException e) { logger.warn("Failed retrieving integer: '{}'", text); return null; @@ -143,4 +144,4 @@ private Position mapPosition(String pos) { } } } -} +} \ No newline at end of file