commit c06ae8317f17454d018cdd9da5b137fda63d4602 Author: vo13crabs Date: Sun Mar 6 01:02:55 2022 +0700 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..78d7f4e --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.idea +*.json +/bin +!/config/new_year_config.json diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..ffc5046 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 3crabs + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..10caf8d --- /dev/null +++ b/README.md @@ -0,0 +1,14 @@ +# student-verochka-bot + +## develop + + git clone https://github.com/3crabs/student-verochka-bot student_bot + cd student_bot + go run main.go --token= --key= + +## deploy + + git clone https://github.com/3crabs/student-verochka-bot student_bot + cd student_bot + go build -v -o bin/bot + ./bin/bot --token= --key= & diff --git a/commands/commands.go b/commands/commands.go new file mode 100644 index 0000000..b6b531f --- /dev/null +++ b/commands/commands.go @@ -0,0 +1,19 @@ +package commands + +type Command string + +//today_lessons - пары сегодня +//tomorrow_lessons - пары завтра +//weather - погода у универа +//new_year - дней до нового года +//ping - проверка связи +//help - помощь +const ( + Start = Command("/start") + Help = Command("/help") + Ping = Command("/ping") + TodayLessons = Command("/today_lessons") + TomorrowLessons = Command("/tomorrow_lessons") + Weather = Command("/weather") + NewYear = Command("/new_year") +) diff --git a/config/new_year_config.json b/config/new_year_config.json new file mode 100644 index 0000000..f9f1693 --- /dev/null +++ b/config/new_year_config.json @@ -0,0 +1,121 @@ +{ + "images": [ + "https://hoteliernews.ru/wp-content/uploads/2018/12/ny.jpg", + "https://klike.net/uploads/posts/2020-01/1580460132_37.jpg", + "https://ryazan.skidkom.ru/static/content/16417/common/magaziny/16417_15662854534276.jpg", + "https://phonoteka.org/uploads/posts/2021-07/1625383153_22-phonoteka-org-p-novogodnie-oboi-na-telefon-uyutnie-oboi-kr-26.jpg", + "https://get.wallhere.com/photo/lights-street-cityscape-night-Christmas-holiday-christmas-lights-tree-beauty-gifts-christmas-decoration-699000.jpg", + "https://images.unsplash.com/photo-1543589077-870d0ba0a43d?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=387&q=80", + "https://images.unsplash.com/photo-1543200226-409d35b65e09?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=435&q=80", + "https://images.unsplash.com/photo-1608686977963-8ccdb7ad2284?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=387&q=80", + "https://images.unsplash.com/photo-1606916929361-b29d5d4a4ad7?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=387&q=80", + "https://images.unsplash.com/photo-1607021145278-5ffe2777fd7e?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=870&q=80", + "https://images.unsplash.com/photo-1576263637347-2aac28621f3d?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=387&q=80", + "https://images.unsplash.com/photo-1512911122913-094837b6fd2f?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=387&q=80", + "https://images.unsplash.com/photo-1606916930054-53ada52915fe?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=387&q=80", + "https://images.unsplash.com/photo-1577725850396-9793fadbd39f?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=387&q=80", + "https://images.unsplash.com/photo-1608302226718-dd9c4bd1ebe4?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=387&q=80", + "https://images.unsplash.com/photo-1575996301730-435a292f104c?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=387&q=80", + "https://images.unsplash.com/photo-1602522785904-8e03a6d65f4f?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=435&q=80", + "https://images.unsplash.com/photo-1577998474517-7eeeed4e448a?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=387&q=80", + "https://images.unsplash.com/photo-1535379665706-aea78de84a41?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=387&q=80", + "https://images.unsplash.com/photo-1531686264889-56fdcabd163f?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=870&q=80", + "https://images.unsplash.com/photo-1500212802521-de7d7426f496?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=387&q=80", + "https://images.unsplash.com/photo-1531574840286-d8d45c1dd989?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=387&q=80", + "https://images.unsplash.com/photo-1514205754505-cde6f571a815?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=387&q=80", + "https://images.unsplash.com/photo-1451772741724-d20990422508?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=870&q=80", + "https://images.unsplash.com/photo-1481271134264-c373cb29cf60?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=870&q=80", + "https://images.unsplash.com/photo-1481366574263-f643ed72bccc?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=869&q=80", + "https://images.unsplash.com/photo-1607322838027-e692e1e0fc7b?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1000&q=80", + "https://images.unsplash.com/photo-1578863235656-1330c3081289?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1000&q=80", + "https://images.unsplash.com/photo-1576326040690-a4e2968bb3b3?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1887&q=80", + "https://images.unsplash.com/photo-1577222959912-2c4ae76903ae?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1770&q=80", + "https://images.unsplash.com/photo-1609034839396-226723bdf413?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1887&q=80", + "https://images.unsplash.com/photo-1576668274938-4cc9da8ee76e?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1770&q=80", + "https://images.unsplash.com/photo-1608478870699-0c4809cccd25?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1886&q=80", + "https://images.unsplash.com/photo-1609009755337-df397a1aa480?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1935&q=80", + "https://ae01.alicdn.com/kf/HTB1g2gUkoF7MKJjSZFLq6AMBVXah/Laeacco-Kerstboom-Pavilion-Sfeer-Straat-Fotografie-Achtergronden-Vinyl-Custom-Fotografische-Achtergronden-Voor-Fotostudio.jpg" + ], + "messages": [ + { + "header": "Мокрый Новый год в Таиланде", + "text": "Тайцы очень любят праздники и не отказываются от лишнего повода повеселиться. Возможно, поэтому они отмечают Новый год трижды: европейский новый год, китайский и свой собственный праздник смены года — Сонгкран. Сонгкран празднуется в апреле несколько дней подряд. В это время тайцы выходят на улицы, чтобы пожелать друг другу счастья и... облить водой с головы до ног. Считается, что чем быстрее и сильнее ты промокнешь, тем больше счастья придет в новом году." + }, + { + "header": "Рождественское полено в странах Европы", + "text": "Во многих европейских странах существовал обычай в рождественский сочельник зажигать в очаге полено. По традиции, полено должно было тлеть в камине на протяжении нескольких дней. В течение этого времени дерево поливали вином и медом, посыпали зерном и клали на него кусочки еды, чтобы год был плодородным и счастливым. Пепел от полена хранили весь год, добавляя его в еду и напитки от всех болезней. С течением времени эта трудоемкая традиция ушла в прошлое, но в память о ней в некоторых европейских странах едят рождественский торт под названием «Полено»." + }, + { + "header": "В Новый год с новым именем в Микронезии", + "text": "На некоторых островах Микронезии каждый год люди берут себе новое имя. 1 января они нашептывают свое новое имя родственникам и друзьям, при этом бьют в барабан или шумят, чтобы их не подслушали злые духи. Из-за этой традиции часто происходят казусы: однажды половина жителей одного из островов весь год носила имя Майкл Джексон." + }, + { + "header": "Мусорный дождь в новогоднюю ночь в Италии", + "text": "В Италии считают, что, вступая в новый год, нужно непременно избавиться от всего старого и ненужного. В канун Нового года темпераментные итальянцы выбрасывают старые вещи прямо из окон своих домов. В былые времена на улицы летела даже сломанная мебель. Сейчас же можно попасть под «обстрел» старыми бумагами и мелким мусором." + }, + { + "header": "С чемоданом вокруг дома в Эквадоре", + "text": "Чтобы год был наполнен множеством путешествий, эквадорцы рекомендуют совершить первое из них прямо в новогоднюю ночь. Для этого нужно обежать вокруг дома с чемоданом в руках, пока часы бьют двенадцать раз." + }, + { + "header": "Виноградины успеха в Испании", + "text": "В винных столицах мира ни одно торжество не обходится без винограда. В Испании для всех участников новогоднего застолья заранее подготавливают по двенадцать виноградин (число ударов новогоднего колокола). Испанцы верят, что если все ягоды будут съедены за двенадцать ударов, год обязательно будет успешным." + }, + { + "header": "Гном и битье посуды в Швеции", + "text": "В Швеции, в отличие от большинства европейских стран, подарки детям приносит не высокий бородатый старик, а гном Юль Томтен. А помогают ему разные зверюшки, тролли, феи, принц с принцессой и даже Снежная Королева. Шведы очень любят разные гадания. В новогоднюю ночь они разбивают тарелки о двери соседей. Чем мельче осколки, тем больше счастья придет в новом году." + }, + { + "header": "Во Вьетнаме Новый год встречают со стариками", + "text": "Вьетнамцы считают, что если за новогодним столом сидит человек старше семидесяти лет, его мудрость распространится на всех присутствующих. И чем старше гость, тем больше почета ему оказывают." + }, + { + "header": "Ожившие сказки Англии и поцелуи под омелой", + "text": "Новый год в Англии отмечается традиционным карнавальным шествием, которое возглавляет Лорд Беспорядок. В толпе сказочных героев можно увидеть Мартовского зайца, Шалтая-Болтая и прочих любимцев детей. Дома и улицы Англии украшаются венками из омелы, которая, по поверьям, обладает магической силой. Во время звона новогоднего колокола влюбленные целуются под таким венком, чтобы жить в согласии." + }, + { + "header": "В Голландии идут в гости со спичками", + "text": "Голландцы идут на новогодний ужин, захватив с собой спичку. Спичка впоследствии сжигается в камине. Если она сгорает полностью, год будет очень счастливым." + }, + { + "header": "Бочка дегтя в Шотландии", + "text": "В некоторых городах Шотландии в новогоднюю ночь поджигают бочки с дегтем и катят их по улицам города. Так сжигают старый год и очищают дорогу новому. Если вам предстоит новогодний ужин у шотландца, не забудьте захватить с собой уголек, чтобы бросить его в очаг хозяина. Таким образом в Шотландии желают удачи в новом году." + }, + { + "header": "Японцы загребают счастье граблями", + "text": "В Японии к Новому году принято украшать дома бамбуковыми граблями. Считается, что если в доме нет граблей, то нечем будет загребать счастье. В первые секунды нового года японцы громко смеются, чтобы год был веселым и радостным." + }, + { + "header": "Во Франции у кого боб, тот и король", + "text": "В католической Франции зимние праздники заканчиваются 6 января на Богоявление. Этот праздник посвящен библейскому сюжету о трех волхвах, которые принесли дары младенцу Христу. В современной Франции в этот день едят знаменитый слоеный пирог с начинкой из миндаля — Пирог Волхвов. Пирог разрезается на части, один из гостей забирается под стол и оттуда выкрикивает, кому какой кусок следует отдать. В прежние времена в пироге запекался боб, и человек, которому он попадался, становился королем вечера. Сейчас в пирог кладут керамическую фигурку и корону из картона." + }, + { + "header": "В Бразилии «море пламенем горит»", + "text": "В жаркой Бразилии в новогоднюю ночь океан сверкает огнями. По традиции, люди загадывают желания и пускают по воде плоты со свечами и дарами богине моря. В прибрежные волны бросают лепестки белых цветов в надежде, что океан примет желания и не выбросит лепестки на берег. Приход Нового года сопровождает выстрел из пушки, после которого бразильцы обнимают всех вокруг, чтобы год был полон любви." + }, + { + "header": "В Венгрии освистывают злых духов", + "text": "Венгры уверены в том, что злые духи очень боятся звука свистков и дудочек. Чтобы наступающий год был счастливым, перед его приходом обязательно нужно очистить города от духов-вредителей. И в новогоднюю ночь Венгрия наполняется громкими трелями и свистом." + }, + { + "header": "Чтобы год был сладким, в Израиле едят сладости", + "text": "В Израиле отмечают Новый год в сентябре. Во время праздника едят сладкую пищу. Даже рыбу поливают медом. От горькой еды стараются отказаться, чтобы не привлечь «горькую» жизнь в новом году." + }, + { + "header": "Кубинцы смывают грехи в новогоднюю ночь", + "text": "В день перед Новым годом на Кубе наливают воду в кружки, тазы и кастрюли. Каждый набирает столько воды, сколько, по его мнению, грехов он совершил за год. После полуночи вода выливается за порог, что символизирует очищение от пороков." + }, + { + "header": "Пауза для поцелуев в Болгарии и кизиловые палочки", + "text": "Во время празднования Нового года в Болгарии во всех домах на три минуты выключают свет. В это время можно поцеловаться с тем, с кем не решался сделать это при свете. А 1 января болгарские дети идут поздравлять взрослых с кизиловыми палочками в руках. Дети стучат палочками друг о друга, после чего получают подарки." + }, + { + "header": "Санта Клаус — серфингист в Австралии", + "text": "Новый год отмечается в Австралии летом. Жара вынуждает Санту избавиться от теплой шубы, и из всего праздничного костюма на нем часто остаются лишь красные плавки, борода и колпак. Оленям жары тоже не вынести, и на санях без снега не проехать, поэтому Санта Клаус доставляет подарки на серфе. Толпа встречает его на пляже радостными криками и фейерверками." + }, + { + "header": "Камень за пазухой в Греции", + "text": "Если вы идете на новогодний ужин в Греции, по дороге обязательно подберите камень побольше. Крупные камни греки кладут у порога хозяина дома с пожеланиями такого же большого богатства. Если же больших камней не нашлось, можно взять самый маленький и пожелать, чтобы возможные беды хозяев были не тяжелее этого камешка." + } + ] +} \ No newline at end of file diff --git a/date/date.go b/date/date.go new file mode 100644 index 0000000..fe4f70e --- /dev/null +++ b/date/date.go @@ -0,0 +1,7 @@ +package date + +import "time" + +func Today() int { + return int(time.Now().Weekday()) +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..7ceddad --- /dev/null +++ b/go.mod @@ -0,0 +1,16 @@ +module student_bot + +go 1.17 + +require ( + github.com/3crabs/go-yandex-weather-api v0.6.0 + github.com/PuerkitoBio/goquery v1.7.1 + github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible + github.com/umputun/go-flags v1.5.1 +) + +require ( + github.com/andybalholm/cascadia v1.3.1 // indirect + github.com/technoweenie/multipartstreamer v1.0.1 // indirect + golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..170195a --- /dev/null +++ b/go.sum @@ -0,0 +1,23 @@ +github.com/3crabs/go-yandex-weather-api v0.6.0 h1:EpqAfaStJNVRNRyYsvUmiNFQYGrQ+eXVP2e+vMWIh08= +github.com/3crabs/go-yandex-weather-api v0.6.0/go.mod h1:MZLPelQjylEK4nPL9g2cpnAPtqzOpF/SrtRGWXK7QHs= +github.com/PuerkitoBio/goquery v1.7.1 h1:oE+T06D+1T7LNrn91B4aERsRIeCLJ/oPSa6xB9FPnz4= +github.com/PuerkitoBio/goquery v1.7.1/go.mod h1:XY0pP4kfraEmmV1O7Uf6XyjoslwsneBbgeDjLYuN8xY= +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/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= +github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog= +github.com/umputun/go-flags v1.5.1 h1:vRauoXV3Ultt1HrxivSxowbintgZLJE+EcBy5ta3/mY= +github.com/umputun/go-flags v1.5.1/go.mod h1:nTbvsO/hKqe7Utri/NoyN18GR3+EWf+9RrmsdwdhrEc= +golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/main.go b/main.go new file mode 100644 index 0000000..5b24fd6 --- /dev/null +++ b/main.go @@ -0,0 +1,135 @@ +package main + +import ( + "errors" + "log" + "math/rand" + "os" + "strings" + "student_bot/commands" + "student_bot/date" + "student_bot/messages" + "student_bot/new_year_service" + "student_bot/parser" + "time" + + weather "github.com/3crabs/go-yandex-weather-api" + tgbot "github.com/go-telegram-bot-api/telegram-bot-api" + "github.com/umputun/go-flags" +) + +type Opts struct { + Token string `short:"t" long:"token" description:"Telegram api token"` + Key string `short:"k" long:"key" description:"Yandex weather API key"` + Name string `short:"n" long:"name" description:"Telegram bot name" default:"@student_verochka_bot"` +} + +var sendMessage = false + +var opts Opts + +func main() { + run() +} + +func run() { + rand.Seed(time.Now().UnixNano()) + + p := flags.NewParser(&opts, flags.PrintErrors|flags.PassDoubleDash|flags.HelpFlag) + p.SubcommandsOptional = true + if _, err := p.Parse(); err != nil { + if err.(*flags.Error).Type != flags.ErrHelp { + log.Println(errors.New("[ERROR] cli error: " + err.Error())) + } + os.Exit(2) + } + + imageService, err := new_year_service.NewNewYearService() + if err != nil { + log.Panicln(err) + } + imageService = new_year_service.NewNewYearServiceLogWrapper(imageService) + + bot, err := tgbot.NewBotAPI(opts.Token) + if err != nil { + log.Panicln(err) + } + + u := tgbot.NewUpdate(0) + u.Timeout = 60 + + updates, err := bot.GetUpdatesChan(u) + if err != nil { + log.Panicln(err) + } + + log.Println("Bot is start up!") + + for update := range updates { + + // empty message + if update.Message == nil { + continue + } + + text := update.Message.Text + chatId := update.Message.Chat.ID + + if strings.Contains(strings.ToLower(text), "спасибо") { + if sendMessage { + _, _ = bot.Send(tgbot.NewMessage(chatId, messages.ThanksMessage())) + sendMessage = false + } + continue + } + sendMessage = false + + command := commands.Command(strings.Replace(text, opts.Name, "", 1)) + switch command { + + case commands.Start: + send(bot, tgbot.NewMessage(chatId, messages.StartMessage())) + + case commands.Help: + send(bot, tgbot.NewMessage(chatId, messages.HelpMessage())) + + case commands.Ping: + send(bot, tgbot.NewMessage(chatId, messages.PongMessage())) + + case commands.TodayLessons: + send(bot, tgbot.NewMessage(chatId, messages.LessonsMessage( + parser.ParseByDay(date.Today()), + "Сегодня, "+update.Message.From.FirstName+", эти пары:", + "Сегодня пар нет", + ))) + + case commands.TomorrowLessons: + send(bot, tgbot.NewMessage(chatId, messages.LessonsMessage( + parser.ParseByDay(date.Today()+1), + "Завтра, "+update.Message.From.FirstName+", эти пары:", + "Завтра пар нет", + ))) + + case commands.Weather: + w, err := weather.GetWeatherWithCache(opts.Key, 53.346853, 83.777012, time.Hour) + if err != nil { + continue + } + send(bot, tgbot.NewMessage(chatId, messages.WeatherMessage(w))) + + case commands.NewYear: + url := imageService.GetRandomImageURL() + message := imageService.GetRandomMessage() + msg := tgbot.NewPhotoShare(chatId, url) + msg.Caption = messages.NewYearMessage(message) + send(bot, msg) + + default: + } + } +} + +func send(bot *tgbot.BotAPI, msg tgbot.Chattable) { + _, _ = bot.Send(msg) + sendMessage = true +} diff --git a/messages/messages.go b/messages/messages.go new file mode 100644 index 0000000..50c98a9 --- /dev/null +++ b/messages/messages.go @@ -0,0 +1,137 @@ +package messages + +import ( + "fmt" + weather "github.com/3crabs/go-yandex-weather-api" + "math/rand" + "strings" + "student_bot/new_year_service" + "student_bot/parser" + "time" +) + +func StartMessage() string { + return "Привет, я Верочка!" +} + +var thanksMessages = []string{ + "Обращайся", + "Пожалуйста", + "Всегда рада помочь", + "Да незачто", + "Всегда к вашим услугим", +} + +func ThanksMessage() string { + return thanksMessages[rand.Intn(len(thanksMessages)-1)] +} + +func HelpMessage() string { + return "Вот чем я могу вам помочь, отправь:\n\n" + + "- /ping отобью pong\n" + + "- /today_lessons покажу расписание на сегодня\n" + + "- /tomorrow_lessons покажу расписание на завтра\n" + + "- /weather покажу погоду у универа\n" + + "- /new_year - посчитаю количество дней до нового года\n" + + "\nНу а больше я пока ничего не умею" +} + +func PongMessage() string { + return "pong" +} + +func LessonsMessage(schedule []parser.Lesson, prefix, emptyText string) string { + if len(schedule) == 0 { + return emptyText + } + + s := "" + if prefix != "" { + s += prefix + "\n\n" + } + for _, l := range schedule { + if strings.Contains(l.User, "Ярных В.В.") { + s += "⭐️ " + } + s += fmt.Sprintf("%s %s (%s)\n", l.Time, l.Name, l.Place) + } + if prefix != "" { + s += "\n" + + "Д — Димитрова 66 (Филологический, социологический)\n" + + "Л — Ленина 61 (Математический и биологический)\n" + + "М — Ленина 61а (Исторический и географический)\n" + + "С — Социалистический 68 (Экономический и юридический)" + } + return s +} + +func WeatherMessage(w weather.Weather) string { + return fmt.Sprintf("Сейчас у универа:\n"+ + "%s\n"+ + "Температура: %d°C\n"+ + "Ощущается как: %d°C\n"+ + "Скорость ветра: %dм/с\n"+ + "\nПогода на %s:\n"+ + "%s\n"+ + "Температура: %d°C\n"+ + "Ощущается как: %d°C\n"+ + "Скорость ветра: %dм/с\n", + w.Fact.GetCondition(), + w.Fact.Temp, + w.Fact.FeelsLike, + w.Fact.WindSpeed, + w.Forecast.Parts[0].GetPartName(), + w.Forecast.Parts[0].GetCondition(), + w.Forecast.Parts[0].TempAvg, + w.Forecast.Parts[0].FeelsLike, + w.Forecast.Parts[0].WindSpeed) +} + +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) + now := time.Now().In(loc) + days := ny.Sub(now).Hours() / 24 + return fmt.Sprintf("❄ %s ❄ \n\n%s\n\n%s", toStrDays(int(days)), message.Header, message.Text) +} + +func toStrDays(days int) string { + if days == 0 { + return "Сегодня новый год!!!" + } + if days == 1 { + return "Новый год завтра!" + } + s := "" + a := days % 10 + if days < 10 { + switch a { + case 2: + s = "дня" + case 3: + s = "дня" + case 4: + s = "дня" + default: + s = "дней" + } + } + if days >= 10 && days < 20 { + s = "дней" + } + if days >= 20 { + switch a { + case 1: + s = "день" + case 2: + s = "дня" + case 3: + s = "дня" + case 4: + s = "дня" + default: + s = "дней" + } + } + return fmt.Sprintf("До нового года %d %s", days, s) +} diff --git a/new_year_service/new_year_service.go b/new_year_service/new_year_service.go new file mode 100644 index 0000000..15d2ca4 --- /dev/null +++ b/new_year_service/new_year_service.go @@ -0,0 +1,58 @@ +package new_year_service + +import ( + "encoding/json" + "io/ioutil" + "math/rand" + "os" +) + +type newYearConfig struct { + Images []string `json:"images"` + Messages []NewYearMessage `json:"messages"` +} + +type NewYearMessage struct { + Header string `json:"header"` + Text string `json:"text"` +} + +type newYearService struct { + images []string + messages []NewYearMessage +} + +func NewNewYearService() (NewYearService, error) { + images, messages, err := readImagesFromConfig() + if err != nil { + return nil, err + } + return &newYearService{images: images, messages: messages}, nil +} + +func (is *newYearService) GetRandomImageURL() string { + return is.images[rand.Intn(len(is.images))] +} + +func (is *newYearService) GetRandomMessage() NewYearMessage { + return is.messages[rand.Intn(len(is.messages))] +} + +func readImagesFromConfig() ([]string, []NewYearMessage, error) { + file, err := os.Open("config/new_year_config.json") + if err != nil { + return nil, nil, err + } + defer func(file *os.File) { + _ = file.Close() + }(file) + bytes, err := ioutil.ReadAll(file) + if err != nil { + return nil, nil, err + } + newYearConfig := &newYearConfig{} + if err := json.Unmarshal(bytes, newYearConfig); err != nil { + return nil, nil, err + } + return newYearConfig.Images, newYearConfig.Messages, nil +} diff --git a/new_year_service/new_year_service_interface.go b/new_year_service/new_year_service_interface.go new file mode 100644 index 0000000..44012dc --- /dev/null +++ b/new_year_service/new_year_service_interface.go @@ -0,0 +1,6 @@ +package new_year_service + +type NewYearService interface { + GetRandomImageURL() string + GetRandomMessage() NewYearMessage +} diff --git a/new_year_service/new_year_service_log_wrapper.go b/new_year_service/new_year_service_log_wrapper.go new file mode 100644 index 0000000..1e7fe1f --- /dev/null +++ b/new_year_service/new_year_service_log_wrapper.go @@ -0,0 +1,21 @@ +package new_year_service + +import "log" + +type newYearServiceLogWrapper struct { + service NewYearService +} + +func NewNewYearServiceLogWrapper(service NewYearService) NewYearService { + return &newYearServiceLogWrapper{service: service} +} + +func (w *newYearServiceLogWrapper) GetRandomImageURL() string { + log.Println("get random image url") + return w.service.GetRandomImageURL() +} + +func (w *newYearServiceLogWrapper) GetRandomMessage() NewYearMessage { + log.Println("get random message") + return w.service.GetRandomMessage() +} diff --git a/parser/parser.go b/parser/parser.go new file mode 100644 index 0000000..6145f63 --- /dev/null +++ b/parser/parser.go @@ -0,0 +1,118 @@ +package parser + +import ( + "github.com/PuerkitoBio/goquery" + "io" + "log" + "net/http" + "strings" +) + +type Lesson struct { + Day int + Number string + Time string + Name string + User string + Place string +} + +func ParseByDay(day int) []Lesson { + return selectLessonsByDay(parse(), day) +} + +func parse() []Lesson { + url := "https://www.asu.ru/timetable/students/12/2129440415/" + + // 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 tr>td, .schedule tr>td[width=\"100%\"]").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 + } + } + n := (k - 1) % 6 + if n == 0 { + l.Number = trim(text) + } + 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++ + }) + 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 { + var todayLessons []Lesson + for _, l := range schedule { + if l.Day == day { + todayLessons = append(todayLessons, l) + } + } + return todayLessons +}