diff --git a/.mvn/wrapper/MavenWrapperDownloader.java b/.mvn/wrapper/MavenWrapperDownloader.java index a45eb6b..9b48111 100644 --- a/.mvn/wrapper/MavenWrapperDownloader.java +++ b/.mvn/wrapper/MavenWrapperDownloader.java @@ -26,20 +26,19 @@ public class MavenWrapperDownloader { * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. */ private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" - + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; + + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; /** - * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to - * use instead of the default one. + * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to use instead of the default one. */ private static final String MAVEN_WRAPPER_PROPERTIES_PATH = - ".mvn/wrapper/maven-wrapper.properties"; + ".mvn/wrapper/maven-wrapper.properties"; /** * Path where the maven-wrapper.jar will be saved to. */ private static final String MAVEN_WRAPPER_JAR_PATH = - ".mvn/wrapper/maven-wrapper.jar"; + ".mvn/wrapper/maven-wrapper.jar"; /** * Name of the property which should be used to override the default download url for the wrapper. @@ -80,7 +79,7 @@ public static void main(String args[]) { if (!outputFile.getParentFile().exists()) { if (!outputFile.getParentFile().mkdirs()) { System.out.println( - "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); + "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); } } System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); diff --git a/README.md b/README.md index 5cdfd8f..c85600c 100755 --- a/README.md +++ b/README.md @@ -2,13 +2,16 @@ # Lovebox Telegram Sender -The app allows to send messages via Telegram Bot to a single Lovebox instance. Text messages and photos with captions +The app allows to send messages via Telegram Bot to a single Lovebox instance. Text messages and +photos with captions are supported. Other message types (e.g. Stickers, Audio, etc.) will lead to a default message. ## Application Setup -To set up the app a few ids and values need to be retrieved on the Lovebox API. The following curl commands help to find -the needed data on an existing account. Make sure you have set up your account via the Android or iOS app already. +To set up the app a few ids and values need to be retrieved on the Lovebox API. The following curl +commands help to find +the needed data on an existing account. Make sure you have set up your account via the Android or +iOS app already. ### Login with Password @@ -129,15 +132,18 @@ curl --location --request POST 'https://app-api.loveboxlove.com/v1/graphql' \ ### Setting up a Telegram Bot -To create a chatbot on Telegram, you need to contact the [@BotFather](https://telegram.me/BotFather), which is a bot +To create a chatbot on Telegram, you need to contact the [@BotFather](https://telegram.me/BotFather) +, which is a bot used to create other bots. -The command you need is `/newbot` which leads to the next steps to create your bot. Follow the instructions and get the +The command you need is `/newbot` which leads to the next steps to create your bot. Follow the +instructions and get the bot `username`, and `token`. ### Adjusting SpringBoot's application.properties -Running the app from the source needs adjustments according to your settings. Adjusting the `application.properties` +Running the app from the source needs adjustments according to your settings. Adjusting +the `application.properties` in the sources or passing them as Java options or CLI arguments to the app. ```properties @@ -157,7 +163,8 @@ bot.token=4072971853:ABEojZ42uNA6YYn_c7DF8RH0UOorqXuveSQ ### Setting Environment Variables e.g. for Docker -The folling snippet can be passed as `.env` and read by the `docker-compose.yml` or used to be passed directly to the +The folling snippet can be passed as `.env` and read by the `docker-compose.yml` or used to be +passed directly to the `docker run` command. ```bash @@ -201,7 +208,8 @@ mvn spring-boot:build-image \ ### Fixing Known Issues with Missing Fonts -Since the app uses fonts, we need to make sure that fonts are part of the docker container. The containers produced +Since the app uses fonts, we need to make sure that fonts are part of the docker container. The +containers produced above throw and exception when using them `java.lang.NullPointerException: Cannot load from short array because "sun.awt.FontConfiguration.head" is null` @@ -209,8 +217,10 @@ above throw and exception when using them post [Prerequisites for Font Support in AdoptOpenJDK ](https://blog.adoptopenjdk.net/2021/01/prerequisites-for-font-support-in-adoptopenjdk/). -After more research, it seems that the only solution to add fonts to the buildpack base image is to create a OCI run -image by extending the base one. See the `Dockerfile.base-cnb` file how a patch with the additional font packages might +After more research, it seems that the only solution to add fonts to the buildpack base image is to +create a OCI run +image by extending the base one. See the `Dockerfile.base-cnb` file how a patch with the additional +font packages might look like. Build the `runImage` locally with the following command. @@ -219,14 +229,16 @@ Build the `runImage` locally with the following command. docker build --no-cache -f Dockerfile.base-cnb -t patbaumgartner/run:base-cnb . ``` -Since we run the pull policy in the `mvn spring-boot:build-image` command with IF_NOT_PRESENT, we need to make sure that +Since we run the pull policy in the `mvn spring-boot:build-image` command with IF_NOT_PRESENT, we +need to make sure that the newest version of the builder is locally available. ``` bash docker pull paketobuildpacks/builder:base ``` -Finally, passing to the `spring-boot-maven-plugin` the `runImage` to build the docker container containing the fonts. +Finally, passing to the `spring-boot-maven-plugin` the `runImage` to build the docker container +containing the fonts. ```bash mvn spring-boot:build-image \ @@ -239,8 +251,10 @@ mvn spring-boot:build-image \ ## Credits -Reverse engineering (unpinning certificates) was done with [APKLab](https://github.com/APKLab/APKLab) and -the [Lovebox APK](https://www.apkmonk.com/app/love.lovebox.loveboxapp/) provided by [apkmonk](https://www.apkmonk.com). +Reverse engineering (unpinning certificates) was done +with [APKLab](https://github.com/APKLab/APKLab) and +the [Lovebox APK](https://www.apkmonk.com/app/love.lovebox.loveboxapp/) provided +by [apkmonk](https://www.apkmonk.com). Postman was used to capture the REST calls from the mobile app. The article [Capturing Http Requests](https://learning.postman.com/docs/sending-requests/capturing-request-data/capturing-http-requests/) covers everything needed. After a Postman diff --git a/pom.xml b/pom.xml index c48af0e..a1fe3d1 100644 --- a/pom.xml +++ b/pom.xml @@ -1,6 +1,7 @@ - + 4.0.0 diff --git a/src/main/java/com/patbaumgartner/lovebox/telegram/sender/services/ImageService.java b/src/main/java/com/patbaumgartner/lovebox/telegram/sender/services/ImageService.java index 8d6d28c..a2c757e 100644 --- a/src/main/java/com/patbaumgartner/lovebox/telegram/sender/services/ImageService.java +++ b/src/main/java/com/patbaumgartner/lovebox/telegram/sender/services/ImageService.java @@ -7,11 +7,9 @@ import java.awt.Graphics2D; import java.awt.Image; import java.awt.image.BufferedImage; -import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; -import java.io.InputStream; import java.util.Arrays; import java.util.Base64; import java.util.NoSuchElementException; @@ -37,7 +35,7 @@ public record ImageService(ResourceLoader resourceLoader) { public static final String FONT_NAME = "Sans"; @SneakyThrows - public Pair resizeImageToPair(File file, String text) { + public Pair resizeImageToPair(File file, String text) { BufferedImage originalImage = ImageIO.read(file); BufferedImage resizedImage = Scalr.resize( @@ -68,7 +66,7 @@ public Pair resizeImageToPair(File file, String text) { } @SneakyThrows - public Pair createTextImageToPair(String message) { + public Pair createTextImageToPair(String message) { BufferedImage image = new BufferedImage(DISPLAY_WIDTH, DISPLAY_HEIGHT, BufferedImage.TYPE_INT_ARGB); Graphics2D graphics = image.createGraphics(); @@ -91,7 +89,7 @@ public Pair createTextImageToPair(String message) { } @SneakyThrows - public Pair createFixedImageToPair() { + public Pair createFixedImageToPair() { Resource resource = resourceLoader.getResource("lovebox.jpeg"); Image image = ImageIO.read(resource.getInputStream()); image = image.getScaledInstance(DISPLAY_WIDTH, DISPLAY_HEIGHT, Image.SCALE_SMOOTH); @@ -147,11 +145,11 @@ protected void drawCenteredMessage(Graphics2D graphics, String text) { } } - protected Pair constructImagePair(BufferedImage image) throws IOException { + protected Pair constructImagePair(BufferedImage image) throws IOException { ByteArrayOutputStream output = new ByteArrayOutputStream(); ImageIO.write(image, "png", output); String base64Image = Base64.getEncoder().encodeToString(output.toByteArray()); - return new Pair("data:image/png;base64," + base64Image, new ByteArrayInputStream(output.toByteArray())); + return new Pair("data:image/png;base64," + base64Image, output.toByteArray()); } } diff --git a/src/main/java/com/patbaumgartner/lovebox/telegram/sender/telegram/LoveboxBot.java b/src/main/java/com/patbaumgartner/lovebox/telegram/sender/telegram/LoveboxBot.java index f02dc02..3eba0b3 100644 --- a/src/main/java/com/patbaumgartner/lovebox/telegram/sender/telegram/LoveboxBot.java +++ b/src/main/java/com/patbaumgartner/lovebox/telegram/sender/telegram/LoveboxBot.java @@ -4,8 +4,8 @@ import com.patbaumgartner.lovebox.telegram.sender.services.LoveboxService; import com.patbaumgartner.lovebox.telegram.sender.utils.Pair; import com.patbaumgartner.lovebox.telegram.sender.utils.Tripple; +import java.io.ByteArrayInputStream; import java.io.File; -import java.io.InputStream; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.ZonedDateTime; @@ -45,7 +45,7 @@ public class LoveboxBot extends TelegramLongPollingBot { @Scheduled(fixedRate = 10_000) public void readMessageBox() { List> messages = loveboxService.getMessagesByBox(); - messages.stream().forEach(p -> { + messages.forEach(p -> { loveboxMessageStore.computeIfPresent(p.left(), (key, value) -> { if (!value.equals(p.right())) { Message message = telegramMessageStore.get(p.left()); @@ -80,7 +80,7 @@ public void onUpdateReceived(Update update) { return; } - Pair imagePair = null; + Pair imagePair = null; // Create Lovebox Image try { @@ -109,7 +109,7 @@ public void onUpdateReceived(Update update) { // Send/respond Message for (long chatId : chatIds) { Message sentMessage = sendPhotoMessage(chatId, text, imagePair, statusTripple); - telegramMessageStore.put(statusTripple.left(), sentMessage); + telegramMessageStore.putIfAbsent(statusTripple.left(), sentMessage); } } } @@ -143,10 +143,10 @@ protected void sendTextMessage(long chatId, String text) { } } - protected Message sendPhotoMessage(long chatId, String text, Pair imagePair, Tripple statusTripple) { + protected Message sendPhotoMessage(long chatId, String text, Pair imagePair, Tripple statusTripple) { SendPhoto message = new SendPhoto(); message.setChatId(String.valueOf(chatId)); - message.setPhoto(new InputFile(imagePair.right(), "image.png")); + message.setPhoto(new InputFile(new ByteArrayInputStream(imagePair.right()), "image.png")); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss z"); String formattedDateTime = ZonedDateTime.of(statusTripple.middle(), ZoneId.of("Europe/London"))