Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
Practice
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Карпов Роман Вячеславович
Practice
Commits
bb0549d9
Commit
bb0549d9
authored
Feb 19, 2025
by
Карпов Роман Вячеславович
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Добавлено задание ВСР 2.5
parent
0ccae5af
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
885 additions
and
0 deletions
+885
-0
.gitignore
ВСР/2.5/.gitignore
+6
-0
main.py
ВСР/2.5/main.py
+879
-0
No files found.
ВСР/2.5/.gitignore
0 → 100644
View file @
bb0549d9
/env/
/databases/
/owm_token.txt
/telegram_token.txt
\ No newline at end of file
ВСР/2.5/main.py
0 → 100644
View file @
bb0549d9
import
asyncio
import
logging
import
sys
import
os
import
random
import
sqlite3
from
datetime
import
datetime
,
UTC
from
dataclasses
import
dataclass
import
calendar
from
typing
import
Any
from
apscheduler.schedulers.asyncio
import
AsyncIOScheduler
from
apscheduler.triggers.interval
import
IntervalTrigger
from
aiogram
import
Bot
,
Dispatcher
,
Router
,
F
from
aiogram.client.default
import
DefaultBotProperties
from
aiogram.filters
import
CommandStart
,
Command
,
CommandObject
from
aiogram.types
import
Message
,
ReplyKeyboardRemove
,
BotCommand
from
aiogram.fsm.context
import
FSMContext
from
aiogram.fsm.state
import
StatesGroup
,
State
from
pyowm.config
import
DEFAULT_CONFIG
as
OWM_DEFAULT_CONFIG
from
pyowm
import
OWM
from
pyowm.weatherapi25.weather
import
Weather
from
pyowm.weatherapi25.location
import
Location
from
pyowm.commons.exceptions
import
NotFoundError
as
OwmNotFoundError
with
open
(
"./telegram_token.txt"
,
"r"
)
as
f
:
TELEGRAM_TOKEN
=
f
.
read
()
with
open
(
"./owm_token.txt"
,
"r"
)
as
f
:
OWM_TOKEN
=
f
.
read
()
OWM_CONFIG
=
OWM_DEFAULT_CONFIG
|
{
'language'
:
'ru'
}
COUNTRY_CODE_TO_COUNTRY_NAME
=
{
'AF'
:
'Афганистан'
,
'AL'
:
'Албания'
,
'DZ'
:
'Алжир'
,
'AS'
:
'Американское Самоа'
,
'AD'
:
'Андорра'
,
'AO'
:
'Ангола'
,
'AI'
:
'Ангилья'
,
'AQ'
:
'Антарктика'
,
'AG'
:
'Антигуа и Барбуда'
,
'AR'
:
'Аргентина'
,
'AM'
:
'Армения'
,
'AW'
:
'Аруба'
,
'AU'
:
'Австралия'
,
'AT'
:
'Австрия'
,
'AZ'
:
'Азербайджан'
,
'BS'
:
'Багамы'
,
'BH'
:
'Бахрейн'
,
'BD'
:
'Бангладешь'
,
'BB'
:
'Барбадос'
,
'BY'
:
'Беларусь'
,
'BE'
:
'Бельгия'
,
'BZ'
:
'Белиз'
,
'BJ'
:
'Бенин'
,
'BM'
:
'Бермуды'
,
'BT'
:
'Бутан'
,
'BO'
:
'Bolivia'
,
'BQ'
:
'Бонэйр'
,
'BA'
:
'Босния и Герцеговина'
,
'BW'
:
'Ботсвана'
,
'BV'
:
'Остров Буве'
,
'BR'
:
'Бразилия'
,
'IO'
:
'Британская территория в Индийском океане'
,
'BN'
:
'Бруней'
,
'BG'
:
'Болгария'
,
'BF'
:
'Буркина-Фасо'
,
'BI'
:
'Бурунди'
,
'KH'
:
'Камбоджа'
,
'CM'
:
'Камерун'
,
'CA'
:
'Канада'
,
'CV'
:
'Кабо-Верде'
,
'KY'
:
'Острова Кайман'
,
'CF'
:
'ЦАР'
,
'TD'
:
'Чад'
,
'CL'
:
'Чили'
,
'CN'
:
'Китай'
,
'CX'
:
'Остров Рождества'
,
'CC'
:
'Кокосовые острова'
,
'CO'
:
'Колумбия'
,
'KM'
:
'Коморы'
,
'CG'
:
'Конго'
,
'CD'
:
'Демократическая республика Конго'
,
'CK'
:
'Острова Кука'
,
'CR'
:
'Коста-Рика'
,
'HR'
:
'Хорватия'
,
'CU'
:
'Куба'
,
'CW'
:
'Кюрасао'
,
'CY'
:
'Кипр'
,
'CZ'
:
'Чехия'
,
'CI'
:
"Кот-д'Ивуар"
,
'DK'
:
'Дания'
,
'DJ'
:
'Джибути'
,
'DM'
:
'Доминика'
,
'DO'
:
'Доминиканская Республика'
,
'EC'
:
'Эквадор'
,
'EG'
:
'Египт'
,
'SV'
:
'Сальвадор'
,
'GQ'
:
'Equatorial Guinea'
,
'ER'
:
'Eritrea'
,
'EE'
:
'Эстония'
,
'ET'
:
'Эфиопия'
,
'FK'
:
'Фолклендские острова'
,
'FO'
:
'Фарерские острова'
,
'FJ'
:
'Фиджи'
,
'FI'
:
'Финляндия'
,
'FR'
:
'Франция'
,
'GF'
:
'Французская Гвиана'
,
'PF'
:
'Французская Полинезия'
,
'TF'
:
'Французские Южные и Антарктические Территории'
,
'GA'
:
'Габон'
,
'GM'
:
'Гамбия'
,
'GE'
:
'Грузия'
,
'DE'
:
'Германия'
,
'GH'
:
'Гана'
,
'GI'
:
'Гибралтар'
,
'GR'
:
'Греция'
,
'GL'
:
'Гренландия'
,
'GD'
:
'Гренада'
,
'GP'
:
'Гваделупа'
,
'GU'
:
'Гуам'
,
'GT'
:
'Гватемала'
,
'GG'
:
'Гернси'
,
'GN'
:
'Гвинея'
,
'GW'
:
'Гвинея-Бисау'
,
'GY'
:
'Гайана'
,
'HT'
:
'Гаити'
,
'HM'
:
'Остров Херд и остров Макдональд'
,
'VA'
:
'Папский Престол (Государство-город Ватикан)'
,
'HN'
:
'Гандурас'
,
'HK'
:
'Гонк Конг'
,
'HU'
:
'Венгрия'
,
'IS'
:
'Исландия'
,
'IN'
:
'Индия'
,
'ID'
:
'Индонезия'
,
'IR'
:
'Иран'
,
'IQ'
:
'Ирак'
,
'IE'
:
'Ирландия'
,
'IM'
:
'остров Мэн'
,
'IL'
:
'Израиль'
,
'IT'
:
'Италия'
,
'JM'
:
'Ямайка'
,
'JP'
:
'Япония'
,
'JE'
:
'Джерси'
,
'JO'
:
'Иордания'
,
'KZ'
:
'Казахстан'
,
'KE'
:
'Кения'
,
'KI'
:
'Кирибати'
,
'KP'
:
"КНДР"
,
'KR'
:
'Корея'
,
'KW'
:
'Кувейт'
,
'KG'
:
'Кыргызстан'
,
'LA'
:
"Лаос"
,
'LV'
:
'Латвия'
,
'LB'
:
'Ливан'
,
'LS'
:
'Лесото'
,
'LR'
:
'Либерия'
,
'LY'
:
'Ливия'
,
'LI'
:
'Лихтенштейн'
,
'LT'
:
'Литва'
,
'LU'
:
'Люксембург'
,
'MO'
:
'Макао'
,
'MK'
:
'Македония'
,
'MG'
:
'Мадагаскар'
,
'MW'
:
'Малави'
,
'MY'
:
'Малайзия'
,
'MV'
:
'Мальдивы'
,
'ML'
:
'Мали'
,
'MT'
:
'Мальта'
,
'MH'
:
'Маршалловы острова'
,
'MQ'
:
'Мартиника'
,
'MR'
:
'Мавритания'
,
'MU'
:
'Маврикий'
,
'YT'
:
'Майотта'
,
'MX'
:
'Мексика'
,
'FM'
:
'Микронезия'
,
'MD'
:
'Молдова'
,
'MC'
:
'Монако'
,
'MN'
:
'Монголия'
,
'ME'
:
'Черногория'
,
'MS'
:
'Montserrat'
,
'MA'
:
'Морокко'
,
'MZ'
:
'Мозамбик'
,
'MM'
:
'Мьянма (Бирма)'
,
'NA'
:
'Намибия'
,
'NR'
:
'Науру'
,
'NP'
:
'Непал'
,
'NL'
:
'Нидерланды'
,
'NC'
:
'Новая Каледония'
,
'NZ'
:
'Новая Зеландия'
,
'NI'
:
'Никарагуа'
,
'NE'
:
'Нигер'
,
'NG'
:
'Нигерия'
,
'NU'
:
'Ниуэ'
,
'NF'
:
'Острова Норфолк'
,
'MP'
:
'Северные Марианские острова'
,
'NO'
:
'Норвегия'
,
'OM'
:
'Оман'
,
'PK'
:
'Пакистан'
,
'PW'
:
'Палау'
,
'PS'
:
'Палестина'
,
'PA'
:
'Панама'
,
'PG'
:
'Папуа Новая Гвинея'
,
'PY'
:
'Парагвай'
,
'PE'
:
'Перу'
,
'PH'
:
'Филипины'
,
'PN'
:
'острова Питкэрн'
,
'PL'
:
'Польша'
,
'PT'
:
'Португалия'
,
'PR'
:
'Пуэрто-Рико'
,
'QA'
:
'Катар'
,
'RO'
:
'Румыния'
,
'RU'
:
'Российская Федерация'
,
'RW'
:
'Руанда'
,
'RE'
:
'Реюньон'
,
'BL'
:
'Сан-Бартелеми'
,
'SH'
:
'остров Святой Елены'
,
'KN'
:
'Сент-Китс и Невис'
,
'LC'
:
'Сент-Люсия'
,
'MF'
:
'Сен-Мертен'
,
'PM'
:
'Сен-Пьер и Микелон'
,
'VC'
:
'Сент-Винсент и Гренадины'
,
'WS'
:
'Самоа'
,
'SM'
:
'Сан-Марино'
,
'ST'
:
'Сан-Томе и Принсипи'
,
'SA'
:
'Саудовская Арабия'
,
'SN'
:
'Сенегал'
,
'RS'
:
'Сербия'
,
'SC'
:
'Сейшеллы'
,
'SL'
:
'Сьерра-Леоне'
,
'SG'
:
'Сингапур'
,
'SX'
:
'Синт-Мартен'
,
'SK'
:
'Словакия'
,
'SI'
:
'Словения'
,
'SB'
:
'Соломоновы острова'
,
'SO'
:
'Сомали'
,
'ZA'
:
'Южная Африка'
,
'GS'
:
'Южная Георгия и Южные Сандвичевы острова'
,
'SS'
:
'Южный Судан'
,
'ES'
:
'Испания'
,
'LK'
:
'Шри Ланка'
,
'SD'
:
'Судан'
,
'SR'
:
'Суринам'
,
'SJ'
:
'Шпицберген и Ян-Майен'
,
'SZ'
:
'Эсватини'
,
'SE'
:
'Швеция'
,
'CH'
:
'Швейцария'
,
'SY'
:
'Сирия'
,
'TW'
:
'Тайвань'
,
'TJ'
:
'Таджикистан'
,
'TZ'
:
'Танзания'
,
'TH'
:
'Тайланд'
,
'TL'
:
'Восточный Тимор'
,
'TG'
:
'Того'
,
'TK'
:
'Токелау'
,
'TO'
:
'Тонга'
,
'TT'
:
'Тринидад и Тобаго'
,
'TN'
:
'Тунис'
,
'TR'
:
'Турция'
,
'TM'
:
'Туркменистан'
,
'TC'
:
'Острова Теркс и Кайкос'
,
'TV'
:
'Тувалу'
,
'UG'
:
'Уганда'
,
'UA'
:
'Украина'
,
'AE'
:
'ОАЭ'
,
'GB'
:
'Великобритания'
,
'US'
:
'США'
,
'UM'
:
'Внешние малые о-ва (США)'
,
'UY'
:
'Уругвай'
,
'UZ'
:
'Узбекистан'
,
'VU'
:
'Ванауту'
,
'VE'
:
'Венесуэла'
,
'VN'
:
'Вьетнам'
,
'VG'
:
'Британские Виргинские острова'
,
'VI'
:
'Американские Виргинские острова'
,
'WF'
:
'острова Уоллис и Футуна'
,
'EH'
:
'Западная Сахара'
,
'YE'
:
'Йемен'
,
'ZM'
:
'Замбия'
,
'ZW'
:
'Зимбабве'
,
"AX"
:
"Аландские острова"
,
}
COUNTRY_CODE_TO_FLAG
=
{
'AF'
:
'🇦🇫'
,
'AL'
:
'🇦🇱'
,
'DZ'
:
'🇩🇿'
,
'AS'
:
'🇦🇸'
,
'AD'
:
'🇦🇩'
,
'AO'
:
'🇦🇴'
,
'AI'
:
'🇦🇮'
,
'AQ'
:
'🇦🇶'
,
'AG'
:
'🇦🇬'
,
'AR'
:
'🇦🇷'
,
'AM'
:
'🇦🇲'
,
'AW'
:
'🇦🇼'
,
'AU'
:
'🇦🇺'
,
'AT'
:
'🇦🇹'
,
'AZ'
:
'🇦🇿'
,
'BS'
:
'🇧🇸'
,
'BH'
:
'🇧🇭'
,
'BD'
:
'🇧🇩'
,
'BB'
:
'🇧🇧'
,
'BY'
:
'🇧🇾'
,
'BE'
:
'🇧🇪'
,
'BZ'
:
'🇧🇿'
,
'BJ'
:
'🇧🇯'
,
'BM'
:
'🇧🇲'
,
'BT'
:
'🇧🇹'
,
'BO'
:
'🇧🇴'
,
'BQ'
:
'🇧🇶'
,
'BA'
:
'🇧🇦'
,
'BW'
:
'🇧🇼'
,
'BV'
:
'🇧🇻'
,
'BR'
:
'🇧🇷'
,
'IO'
:
'🇮🇴'
,
'BN'
:
'🇧🇳'
,
'BG'
:
'🇧🇬'
,
'BF'
:
'🇧🇫'
,
'BI'
:
'🇧🇮'
,
'KH'
:
'🇰🇭'
,
'CM'
:
'🇨🇲'
,
'CA'
:
'🇨🇦'
,
'CV'
:
'🇨🇻'
,
'KY'
:
'🇰🇾'
,
'CF'
:
'🇨🇫'
,
'TD'
:
'🇹🇩'
,
'CL'
:
'🇨🇱'
,
'CN'
:
'🇨🇳'
,
'CX'
:
'🇨🇽'
,
'CC'
:
'🇨🇨'
,
'CO'
:
'🇨🇴'
,
'KM'
:
'🇰🇲'
,
'CG'
:
'🇨🇬'
,
'CD'
:
'🇨🇩'
,
'CK'
:
'🇨🇰'
,
'CR'
:
'🇨🇷'
,
'HR'
:
'🇭🇷'
,
'CU'
:
'🇨🇺'
,
'CW'
:
'🇨🇼'
,
'CY'
:
'🇨🇾'
,
'CZ'
:
'🇨🇿'
,
'CI'
:
'🇨🇮'
,
'DK'
:
'🇩🇰'
,
'DJ'
:
'🇩🇯'
,
'DM'
:
'🇩🇲'
,
'DO'
:
'🇩🇴'
,
'EC'
:
'🇪🇨'
,
'EG'
:
'🇪🇬'
,
'SV'
:
'🇸🇻'
,
'GQ'
:
'🇬🇶'
,
'ER'
:
'🇪🇷'
,
'EE'
:
'🇪🇪'
,
'ET'
:
'🇪🇹'
,
'FK'
:
'🇫🇰'
,
'FO'
:
'🇫🇴'
,
'FJ'
:
'🇫🇯'
,
'FI'
:
'🇫🇮'
,
'FR'
:
'🇫🇷'
,
'GF'
:
'🇬🇫'
,
'PF'
:
'🇵🇫'
,
'TF'
:
'🇹🇫'
,
'GA'
:
'🇬🇦'
,
'GM'
:
'🇬🇲'
,
'GE'
:
'🇬🇪'
,
'DE'
:
'🇩🇪'
,
'GH'
:
'🇬🇭'
,
'GI'
:
'🇬🇮'
,
'GR'
:
'🇬🇷'
,
'GL'
:
'🇬🇱'
,
'GD'
:
'🇬🇩'
,
'GP'
:
'🇬🇵'
,
'GU'
:
'🇬🇺'
,
'GT'
:
'🇬🇹'
,
'GG'
:
'🇬🇬'
,
'GN'
:
'🇬🇳'
,
'GW'
:
'🇬🇼'
,
'GY'
:
'🇬🇾'
,
'HT'
:
'🇭🇹'
,
'HM'
:
'🇭🇲'
,
'VA'
:
'🇻🇦'
,
'HN'
:
'🇭🇳'
,
'HK'
:
'🇭🇰'
,
'HU'
:
'🇭🇺'
,
'IS'
:
'🇮🇸'
,
'IN'
:
'🇮🇳'
,
'ID'
:
'🇮🇩'
,
'IR'
:
'🇮🇷'
,
'IQ'
:
'🇮🇶'
,
'IE'
:
'🇮🇪'
,
'IM'
:
'🇮🇲'
,
'IL'
:
'🇮🇱'
,
'IT'
:
'🇮🇹'
,
'JM'
:
'🇯🇲'
,
'JP'
:
'🇯🇵'
,
'JE'
:
'🇯🇪'
,
'JO'
:
'🇯🇴'
,
'KZ'
:
'🇰🇿'
,
'KE'
:
'🇰🇪'
,
'KI'
:
'🇰🇮'
,
'KP'
:
'🇰🇵'
,
'KR'
:
'🇰🇷'
,
'KW'
:
'🇰🇼'
,
'KG'
:
'🇰🇬'
,
'LA'
:
'🇱🇦'
,
'LV'
:
'🇱🇻'
,
'LB'
:
'🇱🇧'
,
'LS'
:
'🇱🇸'
,
'LR'
:
'🇱🇷'
,
'LY'
:
'🇱🇾'
,
'LI'
:
'🇱🇮'
,
'LT'
:
'🇱🇹'
,
'LU'
:
'🇱🇺'
,
'MO'
:
'🇲🇴'
,
'MK'
:
'🇲🇰'
,
'MG'
:
'🇲🇬'
,
'MW'
:
'🇲🇼'
,
'MY'
:
'🇲🇾'
,
'MV'
:
'🇲🇻'
,
'ML'
:
'🇲🇱'
,
'MT'
:
'🇲🇹'
,
'MH'
:
'🇲🇭'
,
'MQ'
:
'🇲🇶'
,
'MR'
:
'🇲🇷'
,
'MU'
:
'🇲🇺'
,
'YT'
:
'🇾🇹'
,
'MX'
:
'🇲🇽'
,
'FM'
:
'🇫🇲'
,
'MD'
:
'🇲🇩'
,
'MC'
:
'🇲🇨'
,
'MN'
:
'🇲🇳'
,
'ME'
:
'🇲🇪'
,
'MS'
:
'🇲🇸'
,
'MA'
:
'🇲🇦'
,
'MZ'
:
'🇲🇿'
,
'MM'
:
'🇲🇲'
,
'NA'
:
'🇳🇦'
,
'NR'
:
'🇳🇷'
,
'NP'
:
'🇳🇵'
,
'NL'
:
'🇳🇱'
,
'NC'
:
'🇳🇨'
,
'NZ'
:
'🇳🇿'
,
'NI'
:
'🇳🇮'
,
'NE'
:
'🇳🇪'
,
'NG'
:
'🇳🇬'
,
'NU'
:
'🇳🇺'
,
'NF'
:
'🇳🇫'
,
'MP'
:
'🇲🇵'
,
'NO'
:
'🇳🇴'
,
'OM'
:
'🇴🇲'
,
'PK'
:
'🇵🇰'
,
'PW'
:
'🇵🇼'
,
'PS'
:
'🇵🇸'
,
'PA'
:
'🇵🇦'
,
'PG'
:
'🇵🇬'
,
'PY'
:
'🇵🇾'
,
'PE'
:
'🇵🇪'
,
'PH'
:
'🇵🇭'
,
'PN'
:
'🇵🇳'
,
'PL'
:
'🇵🇱'
,
'PT'
:
'🇵🇹'
,
'PR'
:
'🇵🇷'
,
'QA'
:
'🇶🇦'
,
'RO'
:
'🇷🇴'
,
'RU'
:
'🇷🇺'
,
'RW'
:
'🇷🇼'
,
'RE'
:
'🇷🇪'
,
'BL'
:
'🇧🇱'
,
'SH'
:
'🇸🇭'
,
'KN'
:
'🇰🇳'
,
'LC'
:
'🇱🇨'
,
'MF'
:
'🇲🇫'
,
'PM'
:
'🇵🇲'
,
'VC'
:
'🇻🇨'
,
'WS'
:
'🇼🇸'
,
'SM'
:
'🇸🇲'
,
'ST'
:
'🇸🇹'
,
'SA'
:
'🇸🇦'
,
'SN'
:
'🇸🇳'
,
'RS'
:
'🇷🇸'
,
'SC'
:
'🇸🇨'
,
'SL'
:
'🇸🇱'
,
'SG'
:
'🇸🇬'
,
'SX'
:
'🇸🇽'
,
'SK'
:
'🇸🇰'
,
'SI'
:
'🇸🇮'
,
'SB'
:
'🇸🇧'
,
'SO'
:
'🇸🇴'
,
'ZA'
:
'🇿🇦'
,
'GS'
:
'🇬🇸'
,
'SS'
:
'🇸🇸'
,
'ES'
:
'🇪🇸'
,
'LK'
:
'🇱🇰'
,
'SD'
:
'🇸🇩'
,
'SR'
:
'🇸🇷'
,
'SJ'
:
'🇸🇯'
,
'SZ'
:
'🇸🇿'
,
'SE'
:
'🇸🇪'
,
'CH'
:
'🇨🇭'
,
'SY'
:
'🇸🇾'
,
'TW'
:
'🇹🇼'
,
'TJ'
:
'🇹🇯'
,
'TZ'
:
'🇹🇿'
,
'TH'
:
'🇹🇭'
,
'TL'
:
'🇹🇱'
,
'TG'
:
'🇹🇬'
,
'TK'
:
'🇹🇰'
,
'TO'
:
'🇹🇴'
,
'TT'
:
'🇹🇹'
,
'TN'
:
'🇹🇳'
,
'TR'
:
'🇹🇷'
,
'TM'
:
'🇹🇲'
,
'TC'
:
'🇹🇨'
,
'TV'
:
'🇹🇻'
,
'UG'
:
'🇺🇬'
,
'UA'
:
'🇺🇦'
,
'AE'
:
'🇦🇪'
,
'GB'
:
'🇬🇧'
,
'US'
:
'🇺🇸'
,
'UM'
:
'🇺🇲'
,
'UY'
:
'🇺🇾'
,
'UZ'
:
'🇺🇿'
,
'VU'
:
'🇻🇺'
,
'VE'
:
'🇻🇪'
,
'VN'
:
'🇻🇳'
,
'VG'
:
'🇻🇬'
,
'VI'
:
'🇻🇮'
,
'WF'
:
'🇼🇫'
,
'EH'
:
'🇪🇭'
,
'YE'
:
'🇾🇪'
,
'ZM'
:
'🇿🇲'
,
'ZW'
:
'🇿🇼'
,
"AX"
:
'🇦🇽'
,
}
@
dataclass
class
Reminder
:
id
:
int
date
:
int
text
:
str
active
:
bool
=
True
REMINDERS
:
dict
[
int
,
list
[
Reminder
]]
=
{}
WEATHER_COMMAND
=
BotCommand
(
command
=
"weather"
,
description
=
"Получить прогноз погоды"
)
RPS_COMMAND
=
BotCommand
(
command
=
"rps"
,
description
=
"Сыграть в камень, ножницы, бумага"
)
REMINDERS_COMMAND
=
BotCommand
(
command
=
"reminders"
,
description
=
"Получить список всех напоминаний"
)
REMINDER_COMMAND
=
BotCommand
(
command
=
"reminder"
,
description
=
"Создать напоминание"
)
CANCEL_COMMAND
=
BotCommand
(
command
=
"cancel"
,
description
=
"Отменить текущее действие"
)
ALL_COMMANDS
=
[
WEATHER_COMMAND
,
RPS_COMMAND
,
REMINDERS_COMMAND
,
REMINDER_COMMAND
,
CANCEL_COMMAND
]
START_MESSAGE
=
"""
Здравствуйте!
Я бот, созданный при выполнении задания ВСР 2.5 по учебной практике 1 курса в РГПУ им. Герцена.
Мои возможности:
- Показывать текущую погоду в любом городе мира с помощью команды /weather
- Играть в камень, ножницы, бумага с помощью команды /rps
- Создавать напоминания с помощью команды /reminder
"""
owm
=
OWM
(
OWM_TOKEN
,
config
=
OWM_CONFIG
)
mgr
=
owm
.
weather_manager
()
bot
=
Bot
(
token
=
TELEGRAM_TOKEN
,
default
=
DefaultBotProperties
(
parse_mode
=
"html"
))
dp
=
Dispatcher
()
reminder_router
=
Router
()
class
NewReminderState
(
StatesGroup
):
text
=
State
()
date
=
State
()
def
create_reminders_db
(
chat_id
:
int
)
->
None
:
database_file
=
f
"./databases/{chat_id}.db"
if
os
.
path
.
exists
(
database_file
):
os
.
remove
(
database_file
)
with
sqlite3
.
connect
(
database_file
)
as
conn
:
conn
.
execute
(
"CREATE TABLE Reminders (id INTEGER PRIMARY KEY AUTOINCREMENT, expires_in INTEGER, content TEXT)"
)
def
add_reminder
(
chat_id
:
int
,
text
:
str
,
date
:
int
)
->
None
:
database_file
=
f
"./databases/{chat_id}.db"
with
sqlite3
.
connect
(
database_file
)
as
conn
:
cur
=
conn
.
cursor
()
cur
.
execute
(
"INSERT INTO Reminders (expires_in, content) VALUES (?, ?)"
,
(
date
,
text
))
if
not
chat_id
in
REMINDERS
:
REMINDERS
.
update
(
chat_id
,
[])
REMINDERS
[
chat_id
]
.
append
(
Reminder
(
cur
.
lastrowid
,
date
,
text
))
def
get_reminders
(
chat_id
:
int
)
->
list
[
Reminder
]:
database_file
=
f
"./databases/{chat_id}.db"
now
=
datetime
.
now
()
timestamp
=
calendar
.
timegm
(
now
.
timetuple
())
result
=
None
with
sqlite3
.
connect
(
database_file
)
as
conn
:
cur
=
conn
.
cursor
()
cur
.
execute
(
"SELECT * FROM Reminders"
)
result
=
cur
.
fetchall
()
def
row_to_reminder
(
row
:
list
[
Any
])
->
Reminder
:
id
=
int
(
row
[
0
])
date
=
int
(
row
[
1
])
text
=
str
(
row
[
2
])
active
=
timestamp
<
date
return
Reminder
(
id
,
date
,
text
,
active
)
return
list
(
map
(
row_to_reminder
,
result
))
@
dp
.
message
(
CommandStart
())
async
def
command_start_handler
(
message
:
Message
)
->
None
:
await
asyncio
.
to_thread
(
create_reminders_db
,
message
.
chat
.
id
)
await
message
.
answer
(
START_MESSAGE
)
@
dp
.
message
(
Command
(
WEATHER_COMMAND
))
async
def
command_weather_handler
(
message
:
Message
,
command
:
CommandObject
)
->
None
:
if
command
.
args
is
None
or
command
.
args
.
isspace
():
await
message
.
answer
(
"Вы не указали город.
\n
Пример использования: /weather Санкт-Петербург"
)
return
try
:
observation
=
mgr
.
weather_at_place
(
command
.
args
)
except
OwmNotFoundError
:
await
message
.
answer
(
"Город не найден :("
)
return
w
:
Weather
=
observation
.
weather
l
:
Location
=
observation
.
location
detailed_status
:
str
=
w
.
detailed_status
country_name
=
COUNTRY_CODE_TO_COUNTRY_NAME
[
l
.
country
]
temperature
=
w
.
temperature
(
unit
=
"celsius"
)
temp
=
int
(
round
(
temperature
[
"temp"
]))
temp_max
=
int
(
round
(
temperature
[
"temp_max"
]))
temp_min
=
int
(
round
(
temperature
[
"temp_min"
]))
feels_like
=
int
(
round
(
temperature
[
"feels_like"
]))
humidity
=
w
.
humidity
wind
=
w
.
wind
()
wind_speed
=
wind
[
"speed"
]
flag
=
COUNTRY_CODE_TO_FLAG
[
l
.
country
]
await
message
.
answer
(
f
"Место: <b>{l.name}, {country_name} {flag}</b>
\n
Погода: <b>{detailed_status.capitalize()}</b>
\n
Температура: <b>{temp} °C</b>
\n
Макс. температура: <b>{temp_max} °C</b>
\n
Мин. температура: <b>{temp_min} °C</b>
\n
Ощущается как: <b>{feels_like} °C</b>
\n
Влажность: <b>{humidity}
%
</b>
\n
Ветер: <b>{wind_speed} м/c</b>"
)
@
dp
.
message
(
Command
(
REMINDERS_COMMAND
))
async
def
command_reminders_handler
(
message
:
Message
)
->
None
:
reminders
=
await
asyncio
.
to_thread
(
get_reminders
,
message
.
chat
.
id
)
if
len
(
reminders
)
==
0
:
await
message
.
answer
(
"У вас нет активных напоминаний."
)
return
answer
=
"Список напоминаний:
\n\n
"
for
i
,
reminder
in
enumerate
(
reminders
,
start
=
1
):
date
=
datetime
.
fromtimestamp
(
reminder
.
date
,
UTC
)
.
strftime
(
"
%
H:
%
M,
%
d/
%
m/
%
Y"
)
status
=
'
\u231B
'
if
reminder
.
active
else
'
\u2705
'
answer
+=
f
"{i}. {status} [{date}] {reminder.text}
\n\n
"
await
message
.
answer
(
answer
)
@
reminder_router
.
message
(
Command
(
CANCEL_COMMAND
))
@
reminder_router
.
message
(
F
.
text
.
casefold
()
==
"cancel"
)
async
def
new_reminder_cancel
(
message
:
Message
,
state
:
FSMContext
)
->
None
:
current_state
=
await
state
.
get_state
()
if
current_state
is
None
:
await
message
.
answer
(
"Нечего отменять."
,
reply_markup
=
ReplyKeyboardRemove
())
return
await
state
.
clear
()
await
message
.
answer
(
"Создание напоминания отменено."
,
reply_markup
=
ReplyKeyboardRemove
())
@
reminder_router
.
message
(
Command
(
REMINDER_COMMAND
))
async
def
command_new_reminder_handler
(
message
:
Message
,
state
:
FSMContext
)
->
None
:
await
state
.
set_state
(
NewReminderState
.
text
)
await
message
.
answer
(
"Введите текст напоминания"
,
reply_markup
=
ReplyKeyboardRemove
())
@
reminder_router
.
message
(
NewReminderState
.
text
)
async
def
new_reminder_text
(
message
:
Message
,
state
:
FSMContext
)
->
None
:
await
state
.
update_data
(
text
=
message
.
text
)
await
state
.
set_state
(
NewReminderState
.
date
)
await
message
.
answer
(
"Теперь введите время и дату напоминания в формате: ЧЧ:ММ ДД/ММ/ГГГГ
\n
<i>Дата не обязательна, по умолчанию - текущий день</i>"
)
@
reminder_router
.
message
(
NewReminderState
.
date
)
async
def
new_reminder_date
(
message
:
Message
,
state
:
FSMContext
)
->
None
:
example_date
=
"10:20 23/12/2025"
date_time
=
message
.
text
.
split
(
" "
)
if
len
(
date_time
)
==
0
:
await
message
.
answer
(
f
"Вы указали время и дату неправильно.
\n
Пример: <b>{example_date}</b>"
)
return
t
=
date_time
[
0
]
.
split
(
":"
)
if
len
(
t
)
!=
2
:
await
message
.
answer
(
f
"Вы указали время неправильно.
\n\n
Пример: <b>{example_date}</b>"
)
return
try
:
hours
=
int
(
t
[
0
])
except
ValueError
:
await
message
.
answer
(
f
"Вы указали время неправильно.
\n
Пример: <b>{example_date}</b>"
)
return
if
hours
>=
24
:
await
message
.
answer
(
f
"Час должен быть меньше 24.
\n
Пример: <b>{example_date}</b>"
)
return
if
hours
<
0
:
await
message
.
answer
(
f
"Час должен быть больше нуля.
\n
Пример: <b>{example_date}</b>"
)
return
try
:
minutes
=
int
(
t
[
1
])
except
ValueError
:
await
message
.
answer
(
f
"Вы указали время неправильно.
\n
Пример: <b>{example_date}</b>"
)
return
if
minutes
>=
60
:
await
message
.
answer
(
f
"Минуты должны быть меньше 60.
\n
Пример: <b>{example_date}</b>"
)
return
if
minutes
<
0
:
await
message
.
answer
(
f
"Минуты должны быть больше нуля.
\n
Пример: <b>{example_date}</b>"
)
return
today
=
datetime
.
today
()
day
=
today
.
day
month
=
today
.
month
year
=
today
.
year
if
len
(
date_time
)
>
1
:
d
=
date_time
[
1
]
.
split
(
'/'
)
if
len
(
d
)
!=
3
:
await
message
.
answer
(
f
"Вы указали дату неправильно.
\n
Пример: <b>{example_date}</b>"
)
return
try
:
day
=
int
(
d
[
0
])
except
ValueError
:
await
message
.
answer
(
f
"Вы указали дату неправильно.
\n
Пример: <b>{example_date}</b>"
)
return
if
day
<
0
:
await
message
.
answer
(
f
"День не может быть меньше <b>нуля</b>.
\n
Пример: <b>{example_date}</b>"
)
try
:
month
=
int
(
d
[
1
])
except
ValueError
:
await
message
.
answer
(
f
"Вы указали дату неправильно.
\n
Пример: <b>{example_date}</b>"
)
return
if
not
1
<=
month
<=
12
:
await
message
.
answer
(
f
"Месяц должен быть в диапазоне от <b>1</b> до <b>12</b>.
\n
Пример: <b>{example_date}</b>"
)
return
try
:
year
=
int
(
d
[
2
])
except
ValueError
:
await
message
.
answer
(
f
"Вы указали дату неправильно.
\n
Пример: <b>{example_date}</b>"
)
return
_
,
max_days
=
calendar
.
monthrange
(
year
,
month
)
if
day
>
max_days
:
await
message
.
answer
(
f
"Последний день месяца - <b>{max_days}</b>, а не <b>{day}</b>.
\n
Пример: <b>{example_date}</b>"
)
return
date
=
datetime
(
year
,
month
,
day
,
hours
,
minutes
)
timestamp
=
calendar
.
timegm
(
date
.
timetuple
())
data
=
await
state
.
update_data
(
date
=
timestamp
)
await
asyncio
.
to_thread
(
add_reminder
,
message
.
chat
.
id
,
data
[
'text'
],
data
[
'date'
])
await
message
.
answer
(
f
"Напоминание успешно создано!"
)
await
state
.
clear
()
async
def
check_reminders_expiration
()
->
None
:
now
=
datetime
.
now
()
timestamp
=
calendar
.
timegm
(
now
.
timetuple
())
for
chat_id
,
reminders
in
REMINDERS
.
items
():
for
reminder
in
reminders
:
if
reminder
.
active
and
timestamp
>
reminder
.
date
:
reminder
.
active
=
False
date
=
datetime
.
fromtimestamp
(
reminder
.
date
,
UTC
)
.
strftime
(
"
%
H:
%
M,
%
d/
%
m/
%
Y"
)
await
bot
.
send_message
(
chat_id
,
f
"Напоминание:
\n\n
{reminder.text}
\n\n
{date}"
)
ROCK
=
"камень"
PAPER
=
"бумага"
SCISSORS
=
"ножницы"
RPS_VARIANTS
=
[
ROCK
,
PAPER
,
SCISSORS
]
RPS_MAP
=
{
ROCK
:
SCISSORS
,
PAPER
:
ROCK
,
SCISSORS
:
PAPER
}
@
dp
.
message
(
Command
(
RPS_COMMAND
))
async
def
command_rps_handler
(
message
:
Message
,
command
:
CommandObject
)
->
None
:
if
command
.
args
is
None
or
command
.
args
.
isspace
():
await
message
.
answer
(
"Вы не выбрали предмет.
\n
Пример использования: /rps камень"
)
return
if
command
.
args
not
in
RPS_VARIANTS
:
await
message
.
answer
(
f
"Такого варианта нет.
\n
Возможные варианты: {ROCK}, {SCISSORS}, {PAPER}."
)
return
user_variant
=
command
.
args
.
lower
()
variant
=
random
.
choice
(
RPS_VARIANTS
)
if
RPS_MAP
.
get
(
user_variant
)
==
variant
:
await
message
.
answer
(
f
"Вы выиграли! Я загадал: <b>{variant}</b>"
)
elif
RPS_MAP
.
get
(
variant
)
==
user_variant
:
await
message
.
answer
(
f
"Вы проиграли! Я загадал: <b>{variant}</b>"
)
else
:
await
message
.
answer
(
f
"Ничья! Я загадал: <b>{variant}</b>"
)
def
load_all_reminders
()
->
None
:
now
=
datetime
.
now
()
timestamp
=
calendar
.
timegm
(
now
.
timetuple
())
for
address
,
_
,
files
in
os
.
walk
(
"./databases/"
):
for
name
in
files
:
chat_id
=
int
(
name
[:
-
3
])
path
=
os
.
path
.
join
(
address
,
name
)
result
=
None
with
sqlite3
.
connect
(
path
)
as
conn
:
cur
=
conn
.
cursor
()
cur
.
execute
(
"SELECT * FROM Reminders"
)
result
=
cur
.
fetchall
()
reminders
:
list
[
Reminder
]
=
[]
for
id
,
date
,
text
in
result
:
active
=
timestamp
<
date
reminders
.
append
(
Reminder
(
id
,
date
,
text
,
active
=
active
))
REMINDERS
[
chat_id
]
=
reminders
async
def
main
()
->
None
:
await
bot
.
set_my_commands
(
commands
=
ALL_COMMANDS
)
dp
.
include_router
(
reminder_router
)
scheduler
=
AsyncIOScheduler
()
scheduler
.
add_job
(
check_reminders_expiration
,
IntervalTrigger
(
seconds
=
10
))
scheduler
.
start
()
await
dp
.
start_polling
(
bot
)
if
__name__
==
"__main__"
:
logging
.
basicConfig
(
level
=
logging
.
INFO
,
stream
=
sys
.
stdout
)
load_all_reminders
()
asyncio
.
run
(
main
())
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment