Files
todemon/main.go
2025-08-01 01:51:20 +02:00

156 lines
3.9 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"os"
"strings"
"time"
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
)
type Task struct {
ID string `json:"id"`
Content string `json:"content"`
Due *struct {
Date string `json:"date"`
} `json:"due"`
}
var (
todoistToken = os.Getenv("TODOIST_TOKEN")
telegramToken = os.Getenv("TELEGRAM_TOKEN")
chatID = os.Getenv("CHAT_ID")
bot *tgbotapi.BotAPI
overdueTasks = map[string]bool{}
)
func getOverdueTasks() []Task {
log.Println("[INFO] Запрашиваю задачи из Todoist...")
req, _ := http.NewRequest("GET", "https://api.todoist.com/rest/v2/tasks", nil)
req.Header.Set("Authorization", "Bearer "+todoistToken)
resp, err := http.DefaultClient.Do(req)
if err != nil {
log.Println("Ошибка запроса Todoist:", err)
return nil
}
defer resp.Body.Close()
var tasks []Task
if err := json.NewDecoder(resp.Body).Decode(&tasks); err != nil {
log.Println("Ошибка парсинга задач:", err)
return nil
}
now := time.Now().Format("2006-01-02T15:04")
var overdue []Task
for _, task := range tasks {
if task.Due != nil && strings.Compare(task.Due.Date, now) < 0 {
overdue = append(overdue, task)
}
}
return overdue
}
func closeTask(taskID string) {
url := fmt.Sprintf("https://api.todoist.com/rest/v2/tasks/%s/close", taskID)
req, _ := http.NewRequest("POST", url, nil)
req.Header.Set("Authorization", "Bearer "+todoistToken)
http.DefaultClient.Do(req)
}
func getRandomReminderMessage(task Task) string {
reminderMessages := []string{
"⏰ Ну что, сделал уже?! Задача: %s",
"⏰ Эй, не забыл про задачу? %s",
"⏰ Напоминаю о задаче: %s",
"⏰ Задача все еще ждет выполнения: %s",
"⏰ Пора бы уже сделать: %s",
}
randomIndex := time.Now().UnixNano() % int64(len(reminderMessages))
return fmt.Sprintf(reminderMessages[randomIndex], task.Content)
}
func isQuietHours() bool {
// Get current time in CET timezone
cet, err := time.LoadLocation("Europe/Paris") // Paris is in CET
if err != nil {
log.Println("Ошибка загрузки таймзоны:", err)
return false // If we can't determine the time, assume it's not quiet hours
}
now := time.Now().In(cet)
hour := now.Hour()
// Quiet hours are from 23:00 to 08:00
return hour >= 23 || hour < 8
}
func spamCheck() {
// Don't send messages during quiet hours
if isQuietHours() {
log.Println("[INFO] Тихий час (23:00-08:00 CET). Уведомления отключены.")
return
}
tasks := getOverdueTasks()
for _, task := range tasks {
if !overdueTasks[task.ID] {
msg := tgbotapi.NewMessage(toInt64(chatID), fmt.Sprintf("🔥 Просрочено: %s", task.Content))
button := tgbotapi.NewInlineKeyboardMarkup(
tgbotapi.NewInlineKeyboardRow(
tgbotapi.NewInlineKeyboardButtonData("✅ Сделал", task.ID),
),
)
msg.ReplyMarkup = button
bot.Send(msg)
overdueTasks[task.ID] = true
} else {
reminderMessage := getRandomReminderMessage(task)
bot.Send(tgbotapi.NewMessage(toInt64(chatID), reminderMessage))
}
}
}
func toInt64(s string) int64 {
var n int64
fmt.Sscan(s, &n)
return n
}
func main() {
var err error
bot, err = tgbotapi.NewBotAPI(telegramToken)
if err != nil {
log.Fatal("Ошибка запуска бота:", err)
}
log.Println("[INFO] Бот запущен")
u := tgbotapi.NewUpdate(0)
u.Timeout = 60
updates := bot.GetUpdatesChan(u)
ticker := time.NewTicker(1 * time.Hour)
go func() {
spamCheck()
for range ticker.C {
spamCheck()
}
}()
for update := range updates {
if update.CallbackQuery != nil {
taskID := update.CallbackQuery.Data
closeTask(taskID)
bot.Send(tgbotapi.NewMessage(update.CallbackQuery.Message.Chat.ID, "✅ Задача закрыта!"))
delete(overdueTasks, taskID)
}
}
}