From 3ea1e824fdfff53d10d20df1bf561c4b18df63e2 Mon Sep 17 00:00:00 2001 From: tiennm99 Date: Thu, 6 Nov 2025 23:18:49 +0700 Subject: [PATCH] Refactor app tracking to use app info records Replaces string-based app tracking in Group with AppleAppInfo and GoogleAppInfo records, enabling storage of additional metadata (e.g., country for Google apps). Updates all related commands and logic to use the new records, improves command argument handling, and enhances output formatting for app lists and checks. --- .../api/apple/request/AppleAppRequest.java | 6 ++--- .../api/google/GooglePlayScraper.java | 16 +++++------ .../api/google/request/GoogleAppRequest.java | 4 +-- .../storescraperbot/bot/StoreScrapeBot.java | 2 ++ .../bot/command/AddAppleAppCommand.java | 19 ++++++++----- .../bot/command/AddGoogleAppCommand.java | 16 ++++++----- .../bot/command/CheckAppCommand.java | 8 +++--- .../bot/command/CheckAppScoreCommand.java | 17 ++++++------ .../bot/command/DeleteAppleAppCommand.java | 4 +-- .../bot/command/DeleteGoogleAppCommand.java | 4 +-- .../bot/command/ListAppCommand.java | 27 +++++++++++++++---- .../miti99/storescraperbot/model/Admin.java | 6 ++--- .../miti99/storescraperbot/model/Group.java | 6 +++-- .../model/entity/AppleAppInfo.java | 2 +- .../model/entity/GoogleAppInfo.java | 2 +- 15 files changed, 87 insertions(+), 52 deletions(-) diff --git a/src/main/java/com/miti99/storescraperbot/api/apple/request/AppleAppRequest.java b/src/main/java/com/miti99/storescraperbot/api/apple/request/AppleAppRequest.java index 5541cd8..c41b1bc 100644 --- a/src/main/java/com/miti99/storescraperbot/api/apple/request/AppleAppRequest.java +++ b/src/main/java/com/miti99/storescraperbot/api/apple/request/AppleAppRequest.java @@ -1,11 +1,11 @@ package com.miti99.storescraperbot.api.apple.request; -public record AppleAppRequest(String appId, Long id) { +public record AppleAppRequest(String appId, Long id, Boolean ratings) { public AppleAppRequest(String appId) { - this(appId, null); + this(appId, null, true); } public AppleAppRequest(Long id) { - this(null, id); + this(null, id, true); } } diff --git a/src/main/java/com/miti99/storescraperbot/api/google/GooglePlayScraper.java b/src/main/java/com/miti99/storescraperbot/api/google/GooglePlayScraper.java index b643943..f0f5bd7 100644 --- a/src/main/java/com/miti99/storescraperbot/api/google/GooglePlayScraper.java +++ b/src/main/java/com/miti99/storescraperbot/api/google/GooglePlayScraper.java @@ -43,13 +43,13 @@ public class GooglePlayScraper { } } - private static GoogleAppResponse getResponse(String appId) { + private static GoogleAppResponse getResponse(String appId, String country) { boolean isInCache = GoogleAppRepository.INSTANCE.exist(appId); if (isInCache) { var app = GoogleAppRepository.INSTANCE.load(appId); return app.getApp(); } else { - var response = app(new GoogleAppRequest(appId)); + var response = app(new GoogleAppRequest(appId, country)); GoogleAppRepository.INSTANCE.init(appId); var app = GoogleAppRepository.INSTANCE.load(appId); app.setApp(response); @@ -58,8 +58,8 @@ public class GooglePlayScraper { } } - public static LocalDate getLastUpdateOfApp(String appId) { - var response = getResponse(appId); + public static LocalDate getLastUpdateOfApp(String appId, String country) { + var response = getResponse(appId, country); long lastUpdateMillis = 0; if (response != null) { lastUpdateMillis = response.updated(); @@ -69,8 +69,8 @@ public class GooglePlayScraper { return LocalDate.ofInstant(Instant.ofEpochMilli(lastUpdateMillis), ZoneId.systemDefault()); } - public static double getAppScore(String appId) { - var response = getResponse(appId); + public static double getAppScore(String appId, String country) { + var response = getResponse(appId, country); if (response == null) { log.error("response is null"); return 0.0; @@ -78,8 +78,8 @@ public class GooglePlayScraper { return response.score(); } - public static long getAppRatings(String appId) { - var response = getResponse(appId); + public static long getAppRatings(String appId, String country) { + var response = getResponse(appId, country); if (response == null) { log.error("response is null"); return 0L; diff --git a/src/main/java/com/miti99/storescraperbot/api/google/request/GoogleAppRequest.java b/src/main/java/com/miti99/storescraperbot/api/google/request/GoogleAppRequest.java index 68f2ce6..4c2066a 100644 --- a/src/main/java/com/miti99/storescraperbot/api/google/request/GoogleAppRequest.java +++ b/src/main/java/com/miti99/storescraperbot/api/google/request/GoogleAppRequest.java @@ -1,7 +1,7 @@ package com.miti99.storescraperbot.api.google.request; -public record GoogleAppRequest(String appId, String lang, String country) { +public record GoogleAppRequest(String appId, String country) { public GoogleAppRequest(String appId) { - this(appId, "vi", "vn"); + this(appId, "vn"); } } diff --git a/src/main/java/com/miti99/storescraperbot/bot/StoreScrapeBot.java b/src/main/java/com/miti99/storescraperbot/bot/StoreScrapeBot.java index a30cad4..8670c0c 100644 --- a/src/main/java/com/miti99/storescraperbot/bot/StoreScrapeBot.java +++ b/src/main/java/com/miti99/storescraperbot/bot/StoreScrapeBot.java @@ -4,6 +4,7 @@ import com.miti99.storescraperbot.bot.command.AddAppleAppCommand; import com.miti99.storescraperbot.bot.command.AddGoogleAppCommand; import com.miti99.storescraperbot.bot.command.AddGroupCommand; import com.miti99.storescraperbot.bot.command.CheckAppCommand; +import com.miti99.storescraperbot.bot.command.CheckAppScoreCommand; import com.miti99.storescraperbot.bot.command.DeleteAppleAppCommand; import com.miti99.storescraperbot.bot.command.DeleteGroupCommand; import com.miti99.storescraperbot.bot.command.InfoCommand; @@ -34,6 +35,7 @@ public class StoreScrapeBot extends CommandLongPollingTelegramBot { register(DeleteAppleAppCommand.INSTANCE); register(ListAppCommand.INSTANCE); register(CheckAppCommand.INSTANCE); + register(CheckAppScoreCommand.INSTANCE); setMyCommands(); } diff --git a/src/main/java/com/miti99/storescraperbot/bot/command/AddAppleAppCommand.java b/src/main/java/com/miti99/storescraperbot/bot/command/AddAppleAppCommand.java index dac916d..be2d628 100644 --- a/src/main/java/com/miti99/storescraperbot/bot/command/AddAppleAppCommand.java +++ b/src/main/java/com/miti99/storescraperbot/bot/command/AddAppleAppCommand.java @@ -4,6 +4,7 @@ import com.miti99.storescraperbot.api.apple.AppStoreScraper; import com.miti99.storescraperbot.api.apple.request.AppleAppRequest; import com.miti99.storescraperbot.api.apple.response.AppleAppResponse; import com.miti99.storescraperbot.bot.StoreScrapeBotTelegramClient; +import com.miti99.storescraperbot.model.entity.AppleAppInfo; import com.miti99.storescraperbot.repository.AdminRepository; import com.miti99.storescraperbot.repository.GroupRepository; import lombok.extern.log4j.Log4j2; @@ -16,7 +17,9 @@ public class AddAppleAppCommand extends BaseStoreScraperBotCommand { public static final AddAppleAppCommand INSTANCE = new AddAppleAppCommand(); AddAppleAppCommand() { - super("addapple", ". Thêm Apple app vào danh sách theo dõi của nhóm"); + super( + "addapple", + ". Thêm Apple app vào danh sách theo dõi của nhóm. id: iTunes 'trackId', appId: iTunes 'bundleId'"); } @Override @@ -50,7 +53,8 @@ public class AddAppleAppCommand extends BaseStoreScraperBotCommand { } } catch (Exception e) { log.error("request app error for appId: '{}', id: '{}'", appId, id, e); - StoreScrapeBotTelegramClient.INSTANCE.sendMessage(chat.getId(), "Error when request app info"); + StoreScrapeBotTelegramClient.INSTANCE.sendMessage( + chat.getId(), "Error when request app info"); return; } appId = response.appId(); @@ -58,13 +62,16 @@ public class AddAppleAppCommand extends BaseStoreScraperBotCommand { long groupId = chat.getId(); var group = GroupRepository.INSTANCE.load(groupId); - if (group.getAppleApps().contains(appId)) { - StoreScrapeBotTelegramClient.INSTANCE.sendMessage(chat.getId(), "Apple app is already added"); + var finalAppId = appId; + if (group.getAppleApps().stream().anyMatch(app -> finalAppId.equals(app.appId()))) { + StoreScrapeBotTelegramClient.INSTANCE.sendMessage( + chat.getId(), "Apple app %s is already added".formatted(appId)); return; } - group.getAppleApps().add(appId); + group.getAppleApps().add(new AppleAppInfo(appId)); GroupRepository.INSTANCE.save(groupId, group); - StoreScrapeBotTelegramClient.INSTANCE.sendMessage(chat.getId(), "Apple app %s added successfully".formatted(appId)); + StoreScrapeBotTelegramClient.INSTANCE.sendMessage( + chat.getId(), "Apple app %s added successfully".formatted(appId)); } } diff --git a/src/main/java/com/miti99/storescraperbot/bot/command/AddGoogleAppCommand.java b/src/main/java/com/miti99/storescraperbot/bot/command/AddGoogleAppCommand.java index 9a83276..471cbad 100644 --- a/src/main/java/com/miti99/storescraperbot/bot/command/AddGoogleAppCommand.java +++ b/src/main/java/com/miti99/storescraperbot/bot/command/AddGoogleAppCommand.java @@ -4,6 +4,7 @@ import com.miti99.storescraperbot.api.google.GooglePlayScraper; import com.miti99.storescraperbot.api.google.request.GoogleAppRequest; import com.miti99.storescraperbot.api.google.response.GoogleAppResponse; import com.miti99.storescraperbot.bot.StoreScrapeBotTelegramClient; +import com.miti99.storescraperbot.model.entity.GoogleAppInfo; import com.miti99.storescraperbot.repository.AdminRepository; import com.miti99.storescraperbot.repository.GroupRepository; import lombok.extern.log4j.Log4j2; @@ -16,7 +17,9 @@ public class AddGoogleAppCommand extends BaseStoreScraperBotCommand { public static final AddGoogleAppCommand INSTANCE = new AddGoogleAppCommand(); AddGoogleAppCommand() { - super("addgoogle", " [country]. Thêm Google app vào danh sách theo dõi của nhóm. Một số app cần country để hoạt động đúng"); + super( + "addgoogle", + " [country]. Thêm Google app vào danh sách theo dõi của nhóm. Một số app cần country để hoạt động đúng, country mặc định là 'vn'"); } @Override @@ -29,15 +32,16 @@ public class AddGoogleAppCommand extends BaseStoreScraperBotCommand { return; } - if (arguments.length != 1) { + if (arguments.length < 1 || arguments.length > 2) { StoreScrapeBotTelegramClient.INSTANCE.sendMessage(chat.getId(), "Invalid arguments"); return; } var appId = arguments[0]; + var country = arguments.length == 2 ? arguments[1] : "vn"; GoogleAppResponse response = null; try { - response = GooglePlayScraper.app(new GoogleAppRequest(appId)); + response = GooglePlayScraper.app(new GoogleAppRequest(appId, country)); } catch (Exception e) { log.error("request app error for appId: '{}'", appId, e); StoreScrapeBotTelegramClient.INSTANCE.sendMessage( @@ -48,13 +52,13 @@ public class AddGoogleAppCommand extends BaseStoreScraperBotCommand { long groupId = chat.getId(); var group = GroupRepository.INSTANCE.load(groupId); - if (group.getGoogleApps().contains(appId)) { + if (group.getGoogleApps().stream().anyMatch(app -> appId.equals(app.appId()))) { StoreScrapeBotTelegramClient.INSTANCE.sendMessage( - chat.getId(), "Google app is already added"); + chat.getId(), "Google app %s is already added".formatted(appId)); return; } - group.getGoogleApps().add(appId); + group.getGoogleApps().add(new GoogleAppInfo(appId, country)); GroupRepository.INSTANCE.save(groupId, group); StoreScrapeBotTelegramClient.INSTANCE.sendMessage( chat.getId(), "Google app %s added successfully".formatted(appId)); diff --git a/src/main/java/com/miti99/storescraperbot/bot/command/CheckAppCommand.java b/src/main/java/com/miti99/storescraperbot/bot/command/CheckAppCommand.java index be60201..12344ab 100644 --- a/src/main/java/com/miti99/storescraperbot/bot/command/CheckAppCommand.java +++ b/src/main/java/com/miti99/storescraperbot/bot/command/CheckAppCommand.java @@ -44,7 +44,8 @@ public class CheckAppCommand extends BaseStoreScraperBotCommand { sb.append("%-20s | %-10s | %-4s | %-2s\n".formatted("AppId", "Updated", "Days", "OK")); sb.append("-".repeat(46)); sb.append("\n"); - for (var appId : group.getAppleApps()) { + for (var app : group.getAppleApps()) { + var appId = app.appId(); var updated = AppStoreScraper.getAppUpdated(appId); long days = ChronoUnit.DAYS.between(updated, now); boolean passed = days <= Constant.NUM_DAYS_WARNING_NOT_UPDATED; @@ -58,8 +59,9 @@ public class CheckAppCommand extends BaseStoreScraperBotCommand { sb.append("%-20s | %-10s | %-4s | %-2s\n".formatted("AppId", "Updated", "Days", "OK")); sb.append("-".repeat(46)); sb.append("\n"); - for (var appId : group.getGoogleApps()) { - var updated = GooglePlayScraper.getLastUpdateOfApp(appId); + for (var app : group.getGoogleApps()) { + var appId = app.appId(); + var updated = GooglePlayScraper.getLastUpdateOfApp(appId, app.country()); long days = ChronoUnit.DAYS.between(updated, now); boolean passed = days <= Constant.NUM_DAYS_WARNING_NOT_UPDATED; sb.append( diff --git a/src/main/java/com/miti99/storescraperbot/bot/command/CheckAppScoreCommand.java b/src/main/java/com/miti99/storescraperbot/bot/command/CheckAppScoreCommand.java index 850172d..cd9df12 100644 --- a/src/main/java/com/miti99/storescraperbot/bot/command/CheckAppScoreCommand.java +++ b/src/main/java/com/miti99/storescraperbot/bot/command/CheckAppScoreCommand.java @@ -3,10 +3,8 @@ package com.miti99.storescraperbot.bot.command; import com.miti99.storescraperbot.api.apple.AppStoreScraper; import com.miti99.storescraperbot.api.google.GooglePlayScraper; import com.miti99.storescraperbot.bot.StoreScrapeBotTelegramClient; -import com.miti99.storescraperbot.constant.Constant; import com.miti99.storescraperbot.repository.AdminRepository; import com.miti99.storescraperbot.repository.GroupRepository; -import java.time.temporal.ChronoUnit; import org.telegram.telegrambots.meta.api.objects.User; import org.telegram.telegrambots.meta.api.objects.chat.Chat; import org.telegram.telegrambots.meta.generics.TelegramClient; @@ -40,9 +38,10 @@ public class CheckAppScoreCommand extends BaseStoreScraperBotCommand { sb.append("Apple Apps:\n"); sb.append("\n"); sb.append("%-20s | %-10s | %-10s\n".formatted("AppId", "Score", "Reviews")); - sb.append("-".repeat(32)); + sb.append("-".repeat(43)); sb.append("\n"); - for (var appId : group.getAppleApps()) { + for (var app : group.getAppleApps()) { + var appId = app.appId(); double score = AppStoreScraper.getAppScore(appId); long reviews = AppStoreScraper.getAppReviews(appId); sb.append("%-20s | %-10s | %-10s\n".formatted(appId, score, reviews)); @@ -52,11 +51,13 @@ public class CheckAppScoreCommand extends BaseStoreScraperBotCommand { sb.append("Google Apps:\n"); sb.append("\n"); sb.append("%-20s | %-10s | %-10s\n".formatted("AppId", "Score", "Ratings")); - sb.append("-".repeat(46)); + sb.append("-".repeat(43)); sb.append("\n"); - for (var appId : group.getGoogleApps()) { - double score = GooglePlayScraper.getAppScore(appId); - long ratings = GooglePlayScraper.getAppRatings(appId); + for (var app : group.getGoogleApps()) { + var appId = app.appId(); + var country = app.country(); + double score = GooglePlayScraper.getAppScore(appId, country); + long ratings = GooglePlayScraper.getAppRatings(appId, country); sb.append("%-20s | %-10s | %-10s\n".formatted(appId, score, ratings)); } sb.append(""); diff --git a/src/main/java/com/miti99/storescraperbot/bot/command/DeleteAppleAppCommand.java b/src/main/java/com/miti99/storescraperbot/bot/command/DeleteAppleAppCommand.java index 711d14e..1d0b3f1 100644 --- a/src/main/java/com/miti99/storescraperbot/bot/command/DeleteAppleAppCommand.java +++ b/src/main/java/com/miti99/storescraperbot/bot/command/DeleteAppleAppCommand.java @@ -33,12 +33,12 @@ public class DeleteAppleAppCommand extends BaseStoreScraperBotCommand { long groupId = chat.getId(); var group = GroupRepository.INSTANCE.load(groupId); - if (!group.getAppleApps().contains(appId)) { + if (group.getAppleApps().stream().noneMatch(app -> appId.equals(app.appId()))) { StoreScrapeBotTelegramClient.INSTANCE.sendMessage(chat.getId(), "Apple app is not added"); return; } - group.getAppleApps().remove(appId); + group.getAppleApps().removeIf(app -> appId.equals(app.appId())); GroupRepository.INSTANCE.save(groupId, group); StoreScrapeBotTelegramClient.INSTANCE.sendMessage(chat.getId(), "Apple app deleted successfully"); } diff --git a/src/main/java/com/miti99/storescraperbot/bot/command/DeleteGoogleAppCommand.java b/src/main/java/com/miti99/storescraperbot/bot/command/DeleteGoogleAppCommand.java index 0869a7f..912e774 100644 --- a/src/main/java/com/miti99/storescraperbot/bot/command/DeleteGoogleAppCommand.java +++ b/src/main/java/com/miti99/storescraperbot/bot/command/DeleteGoogleAppCommand.java @@ -33,12 +33,12 @@ public class DeleteGoogleAppCommand extends BaseStoreScraperBotCommand { long groupId = chat.getId(); var group = GroupRepository.INSTANCE.load(groupId); - if (!group.getGoogleApps().contains(appId)) { + if (group.getGoogleApps().stream().noneMatch(app -> appId.equals(app.appId()))) { StoreScrapeBotTelegramClient.INSTANCE.sendMessage(chat.getId(), "Google app is not added"); return; } - group.getGoogleApps().remove(appId); + group.getGoogleApps().removeIf(app -> appId.equals(app.appId())); GroupRepository.INSTANCE.save(groupId, group); StoreScrapeBotTelegramClient.INSTANCE.sendMessage( chat.getId(), "Google app deleted successfully"); diff --git a/src/main/java/com/miti99/storescraperbot/bot/command/ListAppCommand.java b/src/main/java/com/miti99/storescraperbot/bot/command/ListAppCommand.java index 49b5546..0654fbc 100644 --- a/src/main/java/com/miti99/storescraperbot/bot/command/ListAppCommand.java +++ b/src/main/java/com/miti99/storescraperbot/bot/command/ListAppCommand.java @@ -11,7 +11,7 @@ public class ListAppCommand extends BaseStoreScraperBotCommand { public static final ListAppCommand INSTANCE = new ListAppCommand(); ListAppCommand() { - super("listapp", ". Thêm Google app vào danh sách theo dõi của nhóm"); + super("listapp", ". Lấy danh sách app đang theo dõi của nhóm"); } @Override @@ -34,13 +34,30 @@ public class ListAppCommand extends BaseStoreScraperBotCommand { var sb = new StringBuilder(); sb.append("Apple Apps:\n"); - for (var appId : group.getAppleApps()) { - sb.append("- %s\n".formatted(appId)); + sb.append("\n"); + sb.append("%-2s | %-20s\n".formatted("#", "AppId")); + sb.append("-".repeat(25)); + sb.append("\n"); + int i = 0; + for (var app : group.getAppleApps()) { + i++; + sb.append("%-2d | %-20s\n".formatted(i,app.appId())); } + sb.append("\n"); + sb.append("\n"); + sb.append("\nGoogle Apps:\n"); - for (var appId : group.getGoogleApps()) { - sb.append("- %s\n".formatted(appId)); + sb.append("\n"); + sb.append("%-2s | %-20s | %-7s\n".formatted("#", "AppId", "Country")); + sb.append("-".repeat(35)); + sb.append("\n"); + i = 0; + for (var app : group.getGoogleApps()) { + i++; + sb.append("%-2s | %-20s | %-7s\n".formatted(i, app.appId(), app.country())); } + sb.append("\n"); + sb.append("\n"); StoreScrapeBotTelegramClient.INSTANCE.sendMessage(chat.getId(), sb.toString()); } diff --git a/src/main/java/com/miti99/storescraperbot/model/Admin.java b/src/main/java/com/miti99/storescraperbot/model/Admin.java index 17be171..3a1dd0c 100644 --- a/src/main/java/com/miti99/storescraperbot/model/Admin.java +++ b/src/main/java/com/miti99/storescraperbot/model/Admin.java @@ -1,10 +1,10 @@ package com.miti99.storescraperbot.model; -import java.util.ArrayList; -import java.util.List; +import java.util.HashSet; +import java.util.Set; import lombok.Getter; @Getter public class Admin extends AbstractModel { - final List groups = new ArrayList<>(); + final Set groups = new HashSet<>(); } diff --git a/src/main/java/com/miti99/storescraperbot/model/Group.java b/src/main/java/com/miti99/storescraperbot/model/Group.java index a15b016..a08b039 100644 --- a/src/main/java/com/miti99/storescraperbot/model/Group.java +++ b/src/main/java/com/miti99/storescraperbot/model/Group.java @@ -1,5 +1,7 @@ package com.miti99.storescraperbot.model; +import com.miti99.storescraperbot.model.entity.AppleAppInfo; +import com.miti99.storescraperbot.model.entity.GoogleAppInfo; import java.util.ArrayList; import java.util.List; import lombok.Getter; @@ -8,6 +10,6 @@ import lombok.Setter; @Getter @Setter public class Group extends AbstractModel { - List appleApps = new ArrayList<>(); - List googleApps = new ArrayList<>(); + List appleApps = new ArrayList<>(); + List googleApps = new ArrayList<>(); } diff --git a/src/main/java/com/miti99/storescraperbot/model/entity/AppleAppInfo.java b/src/main/java/com/miti99/storescraperbot/model/entity/AppleAppInfo.java index 10a6305..454fecb 100644 --- a/src/main/java/com/miti99/storescraperbot/model/entity/AppleAppInfo.java +++ b/src/main/java/com/miti99/storescraperbot/model/entity/AppleAppInfo.java @@ -1,3 +1,3 @@ package com.miti99.storescraperbot.model.entity; -public class AppleAppInfo {} +public record AppleAppInfo(String appId) {} diff --git a/src/main/java/com/miti99/storescraperbot/model/entity/GoogleAppInfo.java b/src/main/java/com/miti99/storescraperbot/model/entity/GoogleAppInfo.java index eb51c94..0b01dd0 100644 --- a/src/main/java/com/miti99/storescraperbot/model/entity/GoogleAppInfo.java +++ b/src/main/java/com/miti99/storescraperbot/model/entity/GoogleAppInfo.java @@ -1,3 +1,3 @@ package com.miti99.storescraperbot.model.entity; -public class GoogleAppInfo {} +public record GoogleAppInfo(String appId, String country) {}