diff --git a/commands/commands.go b/commands/commands.go index b6b531f..a1dec0b 100644 --- a/commands/commands.go +++ b/commands/commands.go @@ -4,6 +4,7 @@ type Command string //today_lessons - пары сегодня //tomorrow_lessons - пары завтра +//all_lessons - пары на несколько дней //weather - погода у универа //new_year - дней до нового года //ping - проверка связи @@ -14,6 +15,7 @@ const ( Ping = Command("/ping") TodayLessons = Command("/today_lessons") TomorrowLessons = Command("/tomorrow_lessons") + AllLessons = Command("/all_lessons") Weather = Command("/weather") NewYear = Command("/new_year") ) diff --git a/date/date.go b/date/date.go index 3b8213f..43551b4 100644 --- a/date/date.go +++ b/date/date.go @@ -2,10 +2,10 @@ package date import "time" -func Today() int { +func Today(offset time.Duration) string { location, err := time.LoadLocation("Asia/Novosibirsk") if err != nil { panic(err) } - return int(time.Now().In(location).Weekday()) + return time.Now().In(location).Add(offset).Format("2006-01-02") } diff --git a/go.mod b/go.mod index 7ceddad..8b9eb65 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.17 require ( github.com/3crabs/go-yandex-weather-api v0.6.0 github.com/PuerkitoBio/goquery v1.7.1 + github.com/erizocosmico/go-ics v0.0.0-20180527181030-697b9000b86f github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible github.com/umputun/go-flags v1.5.1 ) diff --git a/go.sum b/go.sum index 170195a..d380781 100644 --- a/go.sum +++ b/go.sum @@ -5,6 +5,8 @@ github.com/PuerkitoBio/goquery v1.7.1/go.mod h1:XY0pP4kfraEmmV1O7Uf6XyjoslwsneBb github.com/andybalholm/cascadia v1.2.0/go.mod h1:YCyR8vOZT9aZ1CHEd8ap0gMVm2aFgxBp0T0eFw1RUQY= github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c= github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA= +github.com/erizocosmico/go-ics v0.0.0-20180527181030-697b9000b86f h1:IUdUh6y8VDhn5iO/ggBCVb9H0vOI3MDlhDSDCrrSC8Q= +github.com/erizocosmico/go-ics v0.0.0-20180527181030-697b9000b86f/go.mod h1:VFnDugGvBJREsor/aiVcXhvAbyjatl0AKXEaGV9u63I= github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible h1:2cauKuaELYAEARXRkq2LrJ0yDDv1rW7+wrTEdVL3uaU= github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible/go.mod h1:qf9acutJ8cwBUhm1bqgz6Bei9/C/c93FPDljKWwsOgM= github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM= diff --git a/main.go b/main.go index f43a6a1..8575228 100644 --- a/main.go +++ b/main.go @@ -189,6 +189,9 @@ func run() { case commands.TomorrowLessons: sendTomorrowLessonsToChat(bot, chatID, "Завтра, "+update.Message.From.FirstName+", эти пары:") + case commands.AllLessons: + sendAllLessonsToChat(bot, chatID, "Пока знаю про эти пары:") + case commands.Weather: w, err := weather.GetWeatherWithCache(opts.Key, 53.346853, 83.777012, time.Hour) if err != nil { @@ -215,7 +218,7 @@ func sendTodayLessonsToChat(bot *tgbot.BotAPI, chatID int64, prefix string) { tgbot.NewMessage( chatID, messages.LessonsMessage( - parser.ParseByDay(date.Today()), + parser.ParseByDay(date.Today(0)), prefix, "Сегодня пар нет", ), @@ -229,7 +232,7 @@ func sendTomorrowLessonsToChat(bot *tgbot.BotAPI, chatID int64, prefix string) { tgbot.NewMessage( chatID, messages.LessonsMessage( - parser.ParseByDay(date.Today()+1), + parser.ParseByDay(date.Today(24*time.Hour)), prefix, "Завтра пар нет", ), @@ -237,6 +240,20 @@ func sendTomorrowLessonsToChat(bot *tgbot.BotAPI, chatID int64, prefix string) { ) } +func sendAllLessonsToChat(bot *tgbot.BotAPI, chatID int64, prefix string) { + send( + bot, + tgbot.NewMessage( + chatID, + messages.LessonsMessage( + parser.ParseByDay(""), + prefix, + "Пусто", + ), + ), + ) +} + func sendNewYearToChat(bot *tgbot.BotAPI, chatID int64, imageService new_year_service.NewYearService) { url := imageService.GetRandomImageURL() message := imageService.GetRandomMessage() diff --git a/messages/messages.go b/messages/messages.go index 09954fb..398fd9c 100644 --- a/messages/messages.go +++ b/messages/messages.go @@ -29,7 +29,7 @@ func ThanksMessage() string { } func HelpMessage(chatID int64) string { - return "Вот чем я могу вам помочь (v1.3.0), отправь:\n\n" + + return "Вот чем я могу вам помочь (v1.4.0), отправь:\n\n" + "- /ping отобью pong\n" + "- /today_lessons покажу расписание на сегодня\n" + "- /tomorrow_lessons покажу расписание на завтра\n" + @@ -52,11 +52,22 @@ func LessonsMessage(schedule []parser.Lesson, prefix, emptyText string) string { if prefix != "" { s += prefix + "\n\n" } + endDate := "" for _, l := range schedule { + if endDate != l.TimeStart.Format("01.02") { + if endDate != "" { + s += "\n" + } + endDate = l.TimeStart.Format("01.02") + s += endDate + "\n" + } if strings.Contains(l.User, "Ярных В.В.") { s += "⭐️ " } - s += fmt.Sprintf("%s %s (%s)\n", l.Time, l.Name, l.Place) + l.Name = strings.ReplaceAll(l.Name, l.Place, "") + l.Name = strings.ReplaceAll(l.Name, "()", "") + l.Name = strings.TrimSpace(l.Name) + s += fmt.Sprintf("%s %s (%s)\n", l.TimeMsg, l.Name, l.Place) } if prefix != "" { s += "\n" + @@ -92,7 +103,7 @@ func WeatherMessage(w weather.Weather) string { func NewYearMessage(message new_year_service.NewYearMessage) string { loc := time.FixedZone("UTC+7", +7*60*60) - ny := time.Date(2023, 1, 1, 0, 0, 0, 0, loc) + ny := time.Date(2024, 1, 1, 0, 0, 0, 0, loc) now := time.Now().In(loc) days := ny.Sub(now).Hours() / 24 if message.Header != "" { diff --git a/parser/examples/main.go b/parser/examples/main.go index acf2c65..91968e4 100644 --- a/parser/examples/main.go +++ b/parser/examples/main.go @@ -4,9 +4,10 @@ import ( "fmt" "student_bot/date" "student_bot/parser" + "time" ) func main() { - lessons := parser.ParseByDay(date.Today()) + lessons := parser.ParseByDay(date.Today(-48*time.Hour)) fmt.Println(lessons) } diff --git a/parser/parser.go b/parser/parser.go index e084bce..95b155b 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -1,126 +1,54 @@ package parser import ( - "fmt" - "io" - "log" - "net/http" "strings" "time" - "github.com/PuerkitoBio/goquery" + "github.com/erizocosmico/go-ics" ) -const scheduleURLTemplate = "https://www.asu.ru/timetable/students/12/2129440415/?date=%s-%s" - type Lesson struct { - Day int - Number string - Time string - Name string - User string - Place string + Number string + TimeStart time.Time + TimeMsg string + Name string + User string + Place string } -func ParseByDay(day int) []Lesson { +func ParseByDay(day string) []Lesson { return selectLessonsByDay(parse(), day) } func parse() []Lesson { - location, err := time.LoadLocation("Asia/Novosibirsk") + link := "https://www.asu.ru/timetable/students/12/2129440415/?file=2129440415.ics" + calendar, err := ics.ParseCalendar(link, 0, nil) if err != nil { panic(err) } - now := time.Now().In(location) - url := fmt.Sprintf(scheduleURLTemplate, now.Format("20060102"), now.Add(24*time.Hour).Format("20060102")) - // Get html - res, err := http.Get(url) - if err != nil { - log.Fatal(err) - } - defer func(Body io.ReadCloser) { - _ = Body.Close() - }(res.Body) - if res.StatusCode != 200 { - log.Fatalf("status code error: %d %s", res.StatusCode, res.Status) - } - - // Load the HTML document - doc, err := goquery.NewDocumentFromReader(res.Body) - if err != nil { - log.Fatal(err) - } - - // Find the review items - k := 0 var lessons []Lesson - var l Lesson - doc.Find(".schedule_table tr td").Each(func(i int, s *goquery.Selection) { - text := strings.TrimSpace(s.Text()) - if strings.Contains(text, "Понедельник") || - strings.Contains(text, "Вторник") || - strings.Contains(text, "Среда") || - strings.Contains(text, "Четверг") || - strings.Contains(text, "Пятница") || - strings.Contains(text, "Суббота") { - k = 0 - l = Lesson{} - if strings.Contains(text, "Понедельник") { - l.Day = 1 - } - if strings.Contains(text, "Вторник") { - l.Day = 2 - } - if strings.Contains(text, "Среда") { - l.Day = 3 - } - if strings.Contains(text, "Четверг") { - l.Day = 4 - } - if strings.Contains(text, "Пятница") { - l.Day = 5 - } - if strings.Contains(text, "Суббота") { - l.Day = 6 - } + for _, event := range calendar.Events { + l := Lesson{ + Number: "", + TimeStart: event.Start, + TimeMsg: event.Start.Format("15:04") + " - " + event.End.Format("15:04"), + Name: event.Summary, + User: event.Description, + Place: event.Location, } - n := (k - 1) % 6 - if n == 0 { - l.Number = trim(text) + if l.Place == "" { + l.Place = "не приходи" } - if n == 1 { - l.Time = trim(text) - } - if n == 2 { - l.Name = trim(text) - } - if n == 3 { - l.User = trim(text) - } - if n == 4 { - l.Place = trim(text) - if l.Place == "" { - l.Place = "не приходи" - } - lessons = append(lessons, l) - } - k++ - }) + lessons = append(lessons, l) + } return lessons } -func trim(s string) string { - s = strings.Replace(s, "пр.з.", "пр.", -1) - s = strings.Replace(s, " ", "", -1) - s = strings.Replace(s, "\n", " ", -1) - return s -} - -func selectLessonsByDay(schedule []Lesson, day int) []Lesson { +func selectLessonsByDay(schedule []Lesson, day string) []Lesson { var todayLessons []Lesson for _, l := range schedule { - if l.Day == day { + if day == "" || strings.Contains(l.TimeStart.String(), day) { todayLessons = append(todayLessons, l) } }