Initial commit: IFM Telegram Bot (Beta/AethelBetaBot)
- Telegram bot for receiving and analyzing messages, photos, and updates - Photo download support with fileId-based naming - Random photo send feature (text "image" triggers random photo from downloads) - Renamed from itm-telegram-bot to ifm-telegram-bot Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
# Telegram Bot Configuration
|
||||
BOT_TOKEN=8165345099:AAGltLm-4YLACR3EG2b0rp79wAAihJjqzeE
|
||||
BOT_USERNAME=AethelBetaBot
|
||||
@@ -0,0 +1,3 @@
|
||||
# Telegram Bot Configuration
|
||||
BOT_TOKEN=your-bot-token-here
|
||||
BOT_USERNAME=your_bot_username
|
||||
@@ -0,0 +1,156 @@
|
||||
#!/bin/bash
|
||||
|
||||
# IFM Telegram Bot - Process Manager (for testing/analysis)
|
||||
# Usage: ./bot.sh {start|stop|restart|status|logs|tail}
|
||||
|
||||
BOT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
JAR_FILE="$BOT_DIR/target/ifm-telegram-bot-1.0.0-jar-with-dependencies.jar"
|
||||
PID_FILE="$BOT_DIR/bot.pid"
|
||||
LOG_DIR="$BOT_DIR/logs"
|
||||
TMUX_SESSION="ifm-bot"
|
||||
STOP_TIMEOUT=10
|
||||
|
||||
GREEN='\033[0;32m'
|
||||
RED='\033[0;31m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
get_pid() {
|
||||
if [ -f "$PID_FILE" ]; then
|
||||
local pid
|
||||
pid=$(cat "$PID_FILE")
|
||||
if kill -0 "$pid" 2>/dev/null; then
|
||||
echo "$pid"
|
||||
return 0
|
||||
fi
|
||||
rm -f "$PID_FILE"
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
do_start() {
|
||||
local pid
|
||||
if pid=$(get_pid); then
|
||||
echo -e "${YELLOW}Bot is already running (PID: $pid)${NC}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ ! -f "$JAR_FILE" ]; then
|
||||
echo -e "${RED}JAR not found: $JAR_FILE${NC}"
|
||||
echo -e "${YELLOW}Run: mvn clean package -DskipTests${NC}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
mkdir -p "$LOG_DIR"
|
||||
|
||||
# Kill any stale tmux session
|
||||
tmux kill-session -t "$TMUX_SESSION" 2>/dev/null
|
||||
|
||||
# Start bot inside a detached tmux session (UTF-8 for Thai text)
|
||||
tmux new-session -d -s "$TMUX_SESSION" \
|
||||
"cd '$BOT_DIR' && LANG=C.UTF-8 LC_ALL=C.UTF-8 exec java -Dfile.encoding=UTF-8 -jar '$JAR_FILE' >> '$LOG_DIR/console.log' 2>&1"
|
||||
|
||||
sleep 3
|
||||
|
||||
# Find the actual java PID from the tmux session
|
||||
local bot_pid
|
||||
bot_pid=$(tmux list-panes -t "$TMUX_SESSION" -F '#{pane_pid}' 2>/dev/null)
|
||||
# The pane_pid is the shell; find the java child
|
||||
local java_pid
|
||||
java_pid=$(pgrep -P "$bot_pid" -f java 2>/dev/null | head -1)
|
||||
|
||||
if [ -n "$java_pid" ] && kill -0 "$java_pid" 2>/dev/null; then
|
||||
echo "$java_pid" > "$PID_FILE"
|
||||
echo -e "${GREEN}Bot started (PID: $java_pid)${NC}"
|
||||
elif [ -n "$bot_pid" ] && kill -0 "$bot_pid" 2>/dev/null; then
|
||||
# Fallback: use the tmux pane pid
|
||||
echo "$bot_pid" > "$PID_FILE"
|
||||
echo -e "${GREEN}Bot started (PID: $bot_pid)${NC}"
|
||||
else
|
||||
echo -e "${RED}Bot failed to start. Check logs:${NC}"
|
||||
tail -5 "$LOG_DIR/console.log" 2>/dev/null
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
do_stop() {
|
||||
local pid
|
||||
if ! pid=$(get_pid); then
|
||||
echo -e "${YELLOW}Bot is not running${NC}"
|
||||
# Cleanup stale tmux just in case
|
||||
tmux kill-session -t "$TMUX_SESSION" 2>/dev/null
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo -e "${YELLOW}Stopping bot (PID: $pid)...${NC}"
|
||||
kill "$pid"
|
||||
|
||||
for i in $(seq 1 "$STOP_TIMEOUT"); do
|
||||
if ! kill -0 "$pid" 2>/dev/null; then
|
||||
rm -f "$PID_FILE"
|
||||
tmux kill-session -t "$TMUX_SESSION" 2>/dev/null
|
||||
echo -e "${GREEN}Bot stopped${NC}"
|
||||
return 0
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
echo -e "${RED}Force killing...${NC}"
|
||||
kill -9 "$pid" 2>/dev/null
|
||||
rm -f "$PID_FILE"
|
||||
tmux kill-session -t "$TMUX_SESSION" 2>/dev/null
|
||||
echo -e "${GREEN}Bot stopped (forced)${NC}"
|
||||
}
|
||||
|
||||
do_status() {
|
||||
local pid
|
||||
if pid=$(get_pid); then
|
||||
local uptime
|
||||
uptime=$(ps -o etime= -p "$pid" 2>/dev/null | xargs)
|
||||
local mem
|
||||
mem=$(ps -o rss= -p "$pid" 2>/dev/null | awk '{printf "%.1f MB", $1/1024}')
|
||||
echo -e "${GREEN}Bot is running${NC}"
|
||||
echo " PID: $pid"
|
||||
echo " Uptime: $uptime"
|
||||
echo " Memory: $mem"
|
||||
else
|
||||
echo -e "${RED}Bot is not running${NC}"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
do_logs() {
|
||||
if [ -f "$LOG_DIR/console.log" ]; then
|
||||
tail -50 "$LOG_DIR/console.log"
|
||||
else
|
||||
echo -e "${YELLOW}No log file found${NC}"
|
||||
fi
|
||||
}
|
||||
|
||||
do_tail() {
|
||||
if [ -f "$LOG_DIR/console.log" ]; then
|
||||
tail -f "$LOG_DIR/console.log"
|
||||
else
|
||||
echo -e "${YELLOW}No log file found. Start the bot first.${NC}"
|
||||
fi
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
start) do_start ;;
|
||||
stop) do_stop ;;
|
||||
restart) do_stop && sleep 1 && do_start ;;
|
||||
status) do_status ;;
|
||||
logs) do_logs ;;
|
||||
tail) do_tail ;;
|
||||
*)
|
||||
echo "Usage: $0 {start|stop|restart|status|logs|tail}"
|
||||
echo ""
|
||||
echo " start - Start bot in background (tmux)"
|
||||
echo " stop - Stop bot"
|
||||
echo " restart - Restart bot"
|
||||
echo " status - Show PID, uptime, memory"
|
||||
echo " logs - Show last 50 lines of log"
|
||||
echo " tail - Follow log in real-time (Ctrl+C to exit)"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
@@ -0,0 +1,123 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.ifm.telegram</groupId>
|
||||
<artifactId>ifm-telegram-bot</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>IFM Telegram Bot</name>
|
||||
<description>Simple Telegram bot that prints all received messages for analysis</description>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.source>21</maven.compiler.source>
|
||||
<maven.compiler.target>21</maven.compiler.target>
|
||||
<telegrambots.version>6.9.7.1</telegrambots.version>
|
||||
<slf4j.version>2.0.9</slf4j.version>
|
||||
<logback.version>1.4.14</logback.version>
|
||||
<dotenv.version>3.0.0</dotenv.version>
|
||||
<gson.version>2.11.0</gson.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<!-- Telegram Bots API -->
|
||||
<dependency>
|
||||
<groupId>org.telegram</groupId>
|
||||
<artifactId>telegrambots</artifactId>
|
||||
<version>${telegrambots.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- Bridge commons-logging to SLF4J -->
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>jcl-over-slf4j</artifactId>
|
||||
<version>${slf4j.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Logging -->
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>${slf4j.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>${logback.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Environment Variables -->
|
||||
<dependency>
|
||||
<groupId>io.github.cdimascio</groupId>
|
||||
<artifactId>dotenv-java</artifactId>
|
||||
<version>${dotenv.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- JSON (for pretty printing Update objects) -->
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>${gson.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.11.0</version>
|
||||
<configuration>
|
||||
<source>21</source>
|
||||
<target>21</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.3.0</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<mainClass>com.ifm.telegram.App</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<version>3.6.0</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<mainClass>com.ifm.telegram.App</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
<descriptorRefs>
|
||||
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||
</descriptorRefs>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>make-assembly</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.ifm.telegram;
|
||||
|
||||
import io.github.cdimascio.dotenv.Dotenv;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.telegram.telegrambots.meta.TelegramBotsApi;
|
||||
import org.telegram.telegrambots.updatesreceivers.DefaultBotSession;
|
||||
|
||||
public class App {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(App.class);
|
||||
|
||||
public static void main(String[] args) {
|
||||
// Load .env
|
||||
Dotenv dotenv = Dotenv.configure()
|
||||
.ignoreIfMissing()
|
||||
.load();
|
||||
|
||||
String botToken = dotenv.get("BOT_TOKEN");
|
||||
String botUsername = dotenv.get("BOT_USERNAME", "ifm_bot");
|
||||
|
||||
if (botToken == null || botToken.isEmpty()) {
|
||||
logger.error("BOT_TOKEN is required. Set it in .env file.");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
logger.info("Starting IFM Telegram Bot (username: {})", botUsername);
|
||||
|
||||
try {
|
||||
TelegramBotsApi botsApi = new TelegramBotsApi(DefaultBotSession.class);
|
||||
MessagePrinterBot bot = new MessagePrinterBot(botToken, botUsername);
|
||||
botsApi.registerBot(bot);
|
||||
logger.info("Bot registered and polling for updates...");
|
||||
} catch (Exception e) {
|
||||
logger.error("Failed to start bot", e);
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
package com.ifm.telegram;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.telegram.telegrambots.bots.TelegramLongPollingBot;
|
||||
import org.telegram.telegrambots.meta.api.methods.GetFile;
|
||||
import org.telegram.telegrambots.meta.api.methods.send.SendPhoto;
|
||||
import org.telegram.telegrambots.meta.api.objects.File;
|
||||
import org.telegram.telegrambots.meta.api.objects.InputFile;
|
||||
import org.telegram.telegrambots.meta.api.objects.Message;
|
||||
import org.telegram.telegrambots.meta.api.objects.PhotoSize;
|
||||
import org.telegram.telegrambots.meta.api.objects.Update;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Simple Telegram bot that prints all received updates to console.
|
||||
* Useful for analyzing message structure from Telegram.
|
||||
*/
|
||||
public class MessagePrinterBot extends TelegramLongPollingBot {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(MessagePrinterBot.class);
|
||||
private static final Gson gson = new GsonBuilder().setPrettyPrinting().serializeNulls().create();
|
||||
|
||||
private static final String DOWNLOAD_DIR = "downloads";
|
||||
private static final Random random = new Random();
|
||||
|
||||
private final String botUsername;
|
||||
|
||||
public MessagePrinterBot(String botToken, String botUsername) {
|
||||
super(botToken);
|
||||
this.botUsername = botUsername;
|
||||
// Ensure download directory exists
|
||||
try {
|
||||
Files.createDirectories(Paths.get(DOWNLOAD_DIR));
|
||||
} catch (Exception e) {
|
||||
logger.warn("Could not create download directory: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBotUsername() {
|
||||
return botUsername;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdateReceived(Update update) {
|
||||
// Print full Update JSON
|
||||
System.out.println("========== UPDATE RECEIVED ==========");
|
||||
System.out.println(gson.toJson(update));
|
||||
System.out.println("======================================");
|
||||
|
||||
// Print human-readable summary
|
||||
if (update.hasMessage()) {
|
||||
Message msg = update.getMessage();
|
||||
printMessageSummary(msg);
|
||||
|
||||
// If text is "image", send a random photo from downloads
|
||||
if (msg.hasText() && msg.getText().trim().equalsIgnoreCase("image")) {
|
||||
sendRandomPhoto(msg.getChatId().toString());
|
||||
}
|
||||
} else if (update.hasEditedMessage()) {
|
||||
System.out.println("[EDITED MESSAGE]");
|
||||
printMessageSummary(update.getEditedMessage());
|
||||
} else if (update.hasCallbackQuery()) {
|
||||
System.out.println("[CALLBACK QUERY] data=" + update.getCallbackQuery().getData()
|
||||
+ " from=" + update.getCallbackQuery().getFrom().getUserName());
|
||||
} else if (update.hasChannelPost()) {
|
||||
System.out.println("[CHANNEL POST]");
|
||||
printMessageSummary(update.getChannelPost());
|
||||
} else {
|
||||
System.out.println("[OTHER UPDATE TYPE] updateId=" + update.getUpdateId());
|
||||
}
|
||||
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
private void printMessageSummary(Message msg) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("[MESSAGE SUMMARY]\n");
|
||||
sb.append(" chatId: ").append(msg.getChatId()).append("\n");
|
||||
sb.append(" chatType: ").append(msg.getChat().getType()).append("\n");
|
||||
sb.append(" messageId: ").append(msg.getMessageId()).append("\n");
|
||||
sb.append(" from: ").append(msg.getFrom() != null ? msg.getFrom().getUserName() : "null").append("\n");
|
||||
sb.append(" firstName: ").append(msg.getFrom() != null ? msg.getFrom().getFirstName() : "null").append("\n");
|
||||
sb.append(" date: ").append(msg.getDate()).append("\n");
|
||||
|
||||
// Text
|
||||
if (msg.hasText()) {
|
||||
sb.append(" text: ").append(msg.getText()).append("\n");
|
||||
}
|
||||
|
||||
// Photo
|
||||
if (msg.hasPhoto()) {
|
||||
List<PhotoSize> photos = msg.getPhoto();
|
||||
sb.append(" photo: ").append(photos.size()).append(" sizes\n");
|
||||
PhotoSize largest = photos.stream()
|
||||
.max(Comparator.comparingInt(PhotoSize::getFileSize))
|
||||
.orElse(null);
|
||||
if (largest != null) {
|
||||
sb.append(" largest: fileId=").append(largest.getFileId()).append("\n");
|
||||
sb.append(" size=").append(largest.getWidth()).append("x").append(largest.getHeight()).append("\n");
|
||||
sb.append(" fileSize=").append(largest.getFileSize()).append(" bytes\n");
|
||||
}
|
||||
if (msg.getCaption() != null) {
|
||||
sb.append(" caption: ").append(msg.getCaption()).append("\n");
|
||||
}
|
||||
// Download the largest photo
|
||||
if (largest != null) {
|
||||
downloadPhoto(largest);
|
||||
}
|
||||
}
|
||||
|
||||
// Document
|
||||
if (msg.hasDocument()) {
|
||||
sb.append(" document: ").append(msg.getDocument().getFileName()).append("\n");
|
||||
sb.append(" mimeType: ").append(msg.getDocument().getMimeType()).append("\n");
|
||||
sb.append(" fileId: ").append(msg.getDocument().getFileId()).append("\n");
|
||||
sb.append(" fileSize: ").append(msg.getDocument().getFileSize()).append(" bytes\n");
|
||||
if (msg.getCaption() != null) {
|
||||
sb.append(" caption: ").append(msg.getCaption()).append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Voice
|
||||
if (msg.hasVoice()) {
|
||||
sb.append(" voice: duration=").append(msg.getVoice().getDuration()).append("s\n");
|
||||
sb.append(" fileId: ").append(msg.getVoice().getFileId()).append("\n");
|
||||
}
|
||||
|
||||
// Video
|
||||
if (msg.hasVideo()) {
|
||||
sb.append(" video: ").append(msg.getVideo().getDuration()).append("s\n");
|
||||
sb.append(" fileId: ").append(msg.getVideo().getFileId()).append("\n");
|
||||
}
|
||||
|
||||
// Sticker
|
||||
if (msg.hasSticker()) {
|
||||
sb.append(" sticker: ").append(msg.getSticker().getEmoji()).append("\n");
|
||||
sb.append(" fileId: ").append(msg.getSticker().getFileId()).append("\n");
|
||||
}
|
||||
|
||||
// Location
|
||||
if (msg.hasLocation()) {
|
||||
sb.append(" location: ").append(msg.getLocation().getLatitude())
|
||||
.append(",").append(msg.getLocation().getLongitude()).append("\n");
|
||||
}
|
||||
|
||||
// Contact
|
||||
if (msg.hasContact()) {
|
||||
sb.append(" contact: ").append(msg.getContact().getFirstName())
|
||||
.append(" ").append(msg.getContact().getPhoneNumber()).append("\n");
|
||||
}
|
||||
|
||||
// Reply
|
||||
if (msg.getReplyToMessage() != null) {
|
||||
sb.append(" replyTo: messageId=").append(msg.getReplyToMessage().getMessageId()).append("\n");
|
||||
}
|
||||
|
||||
System.out.println(sb);
|
||||
}
|
||||
|
||||
private void sendRandomPhoto(String chatId) {
|
||||
try {
|
||||
java.io.File dir = new java.io.File(DOWNLOAD_DIR);
|
||||
java.io.File[] images = dir.listFiles((d, name) ->
|
||||
name.endsWith(".jpg") || name.endsWith(".jpeg") || name.endsWith(".png"));
|
||||
|
||||
if (images == null || images.length == 0) {
|
||||
logger.info("No images in downloads/ to send");
|
||||
return;
|
||||
}
|
||||
|
||||
java.io.File picked = images[random.nextInt(images.length)];
|
||||
SendPhoto sendPhoto = new SendPhoto();
|
||||
sendPhoto.setChatId(chatId);
|
||||
sendPhoto.setPhoto(new InputFile(picked));
|
||||
sendPhoto.setCaption("Random image: " + picked.getName());
|
||||
execute(sendPhoto);
|
||||
logger.info("Sent random photo: {} to chatId: {}", picked.getName(), chatId);
|
||||
} catch (Exception e) {
|
||||
logger.error("Failed to send random photo: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void downloadPhoto(PhotoSize photo) {
|
||||
try {
|
||||
GetFile getFile = new GetFile(photo.getFileId());
|
||||
File file = execute(getFile);
|
||||
String filePath = file.getFilePath();
|
||||
|
||||
// Use fileId as filename, keep extension from Telegram's file_path
|
||||
String extension = "";
|
||||
if (filePath != null && filePath.contains(".")) {
|
||||
extension = filePath.substring(filePath.lastIndexOf("."));
|
||||
}
|
||||
String savedName = photo.getFileId() + extension;
|
||||
Path savePath = Paths.get(DOWNLOAD_DIR, savedName);
|
||||
|
||||
java.io.File downloaded = downloadFile(file, savePath.toFile());
|
||||
logger.info("Photo saved: {} ({} bytes)", downloaded.getAbsolutePath(), downloaded.length());
|
||||
} catch (Exception e) {
|
||||
logger.error("Failed to download photo: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<configuration>
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- Suppress noisy Telegram/HTTP logs -->
|
||||
<logger name="org.apache.http" level="WARN"/>
|
||||
<logger name="org.telegram" level="INFO"/>
|
||||
|
||||
<root level="INFO">
|
||||
<appender-ref ref="STDOUT"/>
|
||||
</root>
|
||||
</configuration>
|
||||
Reference in New Issue
Block a user