go-tg-screenshot-bot
/
main.go
159 строк · 5.4 Кб
1package main
2
3import (
4"bytes"
5"flag"
6"fmt"
7"image/png"
8"log"
9"net/http"
10"strconv"
11"time"
12
13tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
14"github.com/kbinani/screenshot"
15)
16
17// Структура application содержит конфигурацию и экземпляр бота Telegram.
18type application struct {
19config struct {
20token string // Токен для Telegram API
21debug bool // Режим отладки
22webPort string // Порт для веб-сервера
23}
24tgBot *tgbotapi.BotAPI // Экземпляр бота Telegram
25}
26
27func main() {
28// Конфигурация приложения
29app := configure()
30
31// Запуск прослушивания сообщений Telegram в отдельной горутине
32go listenTg(app)
33
34// Запуск веб-сервера в отдельной горутине
35go listenWeb(app)
36
37// Блокировка основного потока, чтобы программа продолжала работать
38select {}
39}
40
41// configure настраивает приложение и возвращает его экземпляр.
42func configure() *application {
43// Определение флагов командной строки
44token := flag.String("token", "Token", "Enter telegram token")
45debug := flag.Bool("debug", false, "Debug mode")
46port := flag.String("port", "8080", "Web port")
47flag.Parse()
48
49// Создание нового бота Telegram
50bot, err := tgbotapi.NewBotAPI(*token)
51if err != nil {
52log.Panic(err)
53}
54bot.Debug = *debug
55log.Printf("Authorized on account %s", bot.Self.UserName)
56
57// Возврат настроенного экземпляра приложения
58return &application{
59config: struct {
60token string
61debug bool
62webPort string
63}{
64token: *token,
65debug: *debug,
66webPort: *port,
67},
68tgBot: bot,
69}
70}
71
72// listenTg обрабатывает входящие сообщения Telegram.
73func listenTg(app *application) {
74u := tgbotapi.NewUpdate(0)
75u.Timeout = 60
76
77// Получаем канал для чтения обновлений от Telegram
78updates := app.tgBot.GetUpdatesChan(u)
79
80// Обработка каждого обновления
81for update := range updates {
82if update.Message == nil {
83return
84}
85
86// Запускаем обработку сообщения в новой горутине
87go func() {
88disNum, _ := strconv.Atoi(update.Message.Text) // Преобразование текста сообщения в номер дисплея
89fileName, buf := screen(disNum) // Захват экрана
90
91// Подготовка сообщения с изображением для отправки
92msg := tgbotapi.PhotoConfig{
93BaseFile: tgbotapi.BaseFile{
94BaseChat: tgbotapi.BaseChat{
95ChatID: update.Message.From.ID,
96},
97File: tgbotapi.FileReader{
98Name: fileName,
99Reader: buf,
100},
101},
102}
103app.tgBot.Send(&msg) // Отправка сообщения
104}()
105}
106}
107
108// screen выполняет захват экрана для указанного дисплея и возвращает имя файла и буфер с изображением.
109func screen(disNum int) (string, *bytes.Buffer) {
110bounds := screenshot.GetDisplayBounds(disNum) // Получение границ дисплея
111img, err := screenshot.CaptureRect(bounds) // Захват изображения экрана
112if err != nil {
113// Попытка повторного захвата экрана до 5 раз при ошибке
114for i := 0; i < 5; i++ {
115fmt.Printf("Error while capture rect %s. Trying again\n", err.Error())
116time.Sleep(1 * time.Second)
117bounds = screenshot.GetDisplayBounds(disNum)
118img, err = screenshot.CaptureRect(bounds)
119if err == nil {
120break
121}
122}
123if err != nil {
124fmt.Printf("Error while capture rect %s\n", err.Error())
125return "", nil
126}
127}
128// Формирование имени файла
129fileName := fmt.Sprintf("%d_%dx%d.png", disNum, bounds.Dx(), bounds.Dy())
130var buf bytes.Buffer
131png.Encode(&buf, img) // Кодирование изображения в PNG и запись в буфер
132fmt.Printf("#%d : %v \"%s\"\n", disNum, bounds, fileName)
133return fileName, &buf
134}
135
136// listenWeb запускает веб-сервер и обрабатывает HTTP-запросы.
137func listenWeb(app *application) {
138// Обработчик для главной страницы
139http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
140displayNumberStr := r.URL.Query().Get("d") // Получение параметра "d" из запроса
141disNum, _ := strconv.Atoi(displayNumberStr) // Преобразование параметра в номер дисплея
142_, buf := screen(disNum) // Захват экрана
143
144// Устанавливаем заголовки ответа
145w.Header().Set("Content-Type", "image/png")
146w.Header().Set("Content-Length", strconv.Itoa(len(buf.Bytes())))
147
148// Отправляем изображение в ответе
149if _, err := w.Write(buf.Bytes()); err != nil {
150log.Printf("Failed to write image to response: %v", err)
151}
152})
153
154// Запуск веб-сервера на указанном порту
155fmt.Printf("Starting web server on %s", app.config.webPort)
156if err := http.ListenAndServe(":"+app.config.webPort, nil); err != nil {
157log.Fatalf("Server failed to start: %v", err)
158}
159}
160