mirror of
https://github.com/EDeev/y.calendarkin.git
synced 2026-06-15 10:51:00 +03:00
v. 1.0
This commit is contained in:
parent
393127b749
commit
1ee0493327
8 changed files with 932 additions and 0 deletions
318
code/bot.py
Normal file
318
code/bot.py
Normal file
|
|
@ -0,0 +1,318 @@
|
||||||
|
import logging, config, sql, asyncio, wget, os
|
||||||
|
|
||||||
|
from aiogram import Bot, Dispatcher, executor, types
|
||||||
|
from aiogram.types import ParseMode
|
||||||
|
|
||||||
|
from datetime import datetime, time
|
||||||
|
from script import text_ical, message_form, dt_now, delta_time
|
||||||
|
|
||||||
|
# инициализируем токен
|
||||||
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
|
||||||
|
bot = Bot(token=config.TOKEN)
|
||||||
|
dp = Dispatcher(bot)
|
||||||
|
|
||||||
|
# инициализируем соединение с БД
|
||||||
|
du = sql.Users('../db/users.db')
|
||||||
|
dc = sql.Clock('../db/clock.db')
|
||||||
|
|
||||||
|
|
||||||
|
# ПРИВЕТСТВЕННОЕ СООБЩЕНИЕ
|
||||||
|
@dp.message_handler(commands=['start', 'help'])
|
||||||
|
async def helps(message: types.Message):
|
||||||
|
tg_id = int(message.chat.id)
|
||||||
|
if not du.user_exists(tg_id):
|
||||||
|
du.add_user(tg_id)
|
||||||
|
|
||||||
|
buttons = [types.InlineKeyboardButton(text="КОМАНДЫ", callback_data="com"),
|
||||||
|
types.InlineKeyboardButton(text="АВТОР", callback_data="auth")]
|
||||||
|
|
||||||
|
keyboard = types.InlineKeyboardMarkup(row_width=2)
|
||||||
|
keyboard.add(*buttons)
|
||||||
|
|
||||||
|
await message.answer(text="<b>Я.Календаркин</b> - бот для оповещения о событиях из <b>Яндекс.Календаря</b>. "
|
||||||
|
"Для начала работы вам нужно всего лишь прислать в чат ссылку экспорта календаря в "
|
||||||
|
"<b>формате ICal</b>. После получения ссылки, бот начнёт оповещать о всех новых событиях "
|
||||||
|
"и появится возможность настройки оповещений. О том, какие команды есть для настройки, "
|
||||||
|
"вы можете ознакомиться по кнопке <b>КОМАНДЫ</b>",
|
||||||
|
parse_mode=ParseMode.HTML, reply_markup=keyboard)
|
||||||
|
|
||||||
|
|
||||||
|
@dp.callback_query_handler(text="auth")
|
||||||
|
async def author(call: types.CallbackQuery):
|
||||||
|
await call.message.answer(text='*| АВТОР |*\n\n*>>* Этот бот не коммерческий проект, для упрощенного получения '
|
||||||
|
'уведомлений о событиях в Яндекс.Календаре. Не многим этот бот будет полезен, но '
|
||||||
|
'людям, чья работа подразумевает его использование, он станет лишь удобным '
|
||||||
|
'инструментом. Я же пишу подобные небольшие проекты, о которых вы можете узнать '
|
||||||
|
'больше на моём [GitHub](https://github.com/IGlek).',
|
||||||
|
parse_mode=ParseMode.MARKDOWN)
|
||||||
|
|
||||||
|
|
||||||
|
@dp.callback_query_handler(text="com")
|
||||||
|
async def commands(call: types.CallbackQuery):
|
||||||
|
await call.message.answer(text='<b>| КОМАНДЫ |</b>\n\n'
|
||||||
|
'<b>/help</b> - вспомогательная функция для уточнения работы команд\n'
|
||||||
|
'<b>/list</b> - список событий календаря, запланированных на сегодняшний день\n'
|
||||||
|
'<b>/notif</b> - команда, отключающая рассылку уведомлений, даже при наличии событий в календаре\n'
|
||||||
|
'<b>/daily</b> - оповещение в 8 утра по вашему часовому поясу со списком событий на день\n'
|
||||||
|
'<b>/moment</b> - напоминание, приходящее в момент начала события\n\n'
|
||||||
|
'<b>/get_alarm</b> - информация о времени на которое настроены оповещения\n'
|
||||||
|
'<b>/edit_alarm</b> - изменение времени оповещений\n'
|
||||||
|
'<b>/stop_alarm</b> - команда, отключающая второе оповещение о событии',
|
||||||
|
parse_mode=types.ParseMode.HTML)
|
||||||
|
|
||||||
|
|
||||||
|
# КОМАНДЫ
|
||||||
|
@dp.message_handler(commands=['list'])
|
||||||
|
async def check_list(message: types.Message):
|
||||||
|
user_id = du.get_user_id(int(message.chat.id))
|
||||||
|
|
||||||
|
if du.url_exists(user_id):
|
||||||
|
txt = "<b>Имеющиеся события на сегодня</b>\n\n"
|
||||||
|
|
||||||
|
lst_events = sorted(text_ical(user_id, du.get_tz(user_id)))
|
||||||
|
today = dt_now(du.get_tz(user_id)).date()
|
||||||
|
|
||||||
|
counter = 0
|
||||||
|
for event in lst_events:
|
||||||
|
if event[0] == today:
|
||||||
|
counter += 1
|
||||||
|
txt += message_form(counter, event[3])
|
||||||
|
|
||||||
|
await message.answer(text=txt, parse_mode=ParseMode.HTML)
|
||||||
|
else:
|
||||||
|
await message.answer("Для отображения событий вы должны прислать ical-ссылку на календарь!")
|
||||||
|
|
||||||
|
|
||||||
|
@dp.message_handler(commands=['notif'])
|
||||||
|
async def notif_up(message: types.Message):
|
||||||
|
user_id = du.get_user_id(int(message.chat.id))
|
||||||
|
|
||||||
|
if du.url_exists(user_id):
|
||||||
|
if du.get_status(user_id):
|
||||||
|
await message.answer("Уведомления о событиях выключены!")
|
||||||
|
else:
|
||||||
|
await message.answer("Уведомления о событиях включены!")
|
||||||
|
|
||||||
|
du.update_status(user_id)
|
||||||
|
else:
|
||||||
|
await message.answer("Для взаимодействия с событиями вы должны прислать ical-ссылку на календарь!")
|
||||||
|
|
||||||
|
|
||||||
|
@dp.message_handler(commands=['daily'])
|
||||||
|
async def daily_up(message: types.Message):
|
||||||
|
user_id = du.get_user_id(int(message.chat.id))
|
||||||
|
|
||||||
|
if dc.clock_exists(user_id):
|
||||||
|
if dc.get_daily(user_id):
|
||||||
|
await message.answer("Ежедневные утренние уведомления выключены!")
|
||||||
|
else:
|
||||||
|
await message.answer("Ежедневные утренние уведомления включены!")
|
||||||
|
|
||||||
|
dc.update_daily(user_id)
|
||||||
|
else:
|
||||||
|
await message.answer("Для взаимодействия с событиями вы должны прислать ical-ссылку на календарь!")
|
||||||
|
|
||||||
|
|
||||||
|
@dp.message_handler(commands=['moment'])
|
||||||
|
async def start_up(message: types.Message):
|
||||||
|
user_id = du.get_user_id(int(message.chat.id))
|
||||||
|
|
||||||
|
if dc.clock_exists(user_id):
|
||||||
|
if dc.get_start(user_id):
|
||||||
|
await message.answer("Уведомления в момент события выключены!")
|
||||||
|
else:
|
||||||
|
await message.answer("Уведомления в момент события включены!")
|
||||||
|
|
||||||
|
dc.update_start(user_id)
|
||||||
|
else:
|
||||||
|
await message.answer("Для взаимодействия с событиями вы должны прислать ical-ссылку на календарь!")
|
||||||
|
|
||||||
|
|
||||||
|
@dp.message_handler(commands=['get_alarm'])
|
||||||
|
async def start_up(message: types.Message):
|
||||||
|
user_id = du.get_user_id(int(message.chat.id))
|
||||||
|
|
||||||
|
if dc.clock_exists(user_id):
|
||||||
|
alarms = dc.get_alarm(user_id)
|
||||||
|
start = dc.get_start(user_id)
|
||||||
|
status2 = dc.get_status2(user_id)
|
||||||
|
|
||||||
|
txt = ""
|
||||||
|
|
||||||
|
if status2:
|
||||||
|
txt += "<b>У вас работает два оповещения"
|
||||||
|
else:
|
||||||
|
txt += "<b>У вас работает лишь первое оповещение"
|
||||||
|
|
||||||
|
if start:
|
||||||
|
txt += " и сообщение в момент начала события!</b>"
|
||||||
|
else:
|
||||||
|
txt += "!</b>"
|
||||||
|
|
||||||
|
await message.answer(text=(txt + f"\n\n<b>Первое оповещение</b> приходит за {alarms[0]} минут\n"
|
||||||
|
f"<b>Второе оповещение</b> приходит за {alarms[1]} минут"),
|
||||||
|
parse_mode=ParseMode.HTML)
|
||||||
|
else:
|
||||||
|
await message.answer("Для того, чтобы получить таймеры, вы должны прислать ical-ссылку на свой календарь!")
|
||||||
|
|
||||||
|
|
||||||
|
@dp.message_handler(commands=['edit_alarm'])
|
||||||
|
async def start_up(message: types.Message):
|
||||||
|
user_id = du.get_user_id(int(message.chat.id))
|
||||||
|
|
||||||
|
if dc.clock_exists(user_id):
|
||||||
|
await message.bot.send_photo(chat_id=message.chat.id, photo=open("../data/photo_edit_alarm.jpg", "rb"),
|
||||||
|
caption="Для изменения времени вам надо в ответ на это сообщение прислать два "
|
||||||
|
"числа через пробел: разница времени первого и второго таймера по ходу "
|
||||||
|
"времени соответственно")
|
||||||
|
else:
|
||||||
|
await message.answer("Для того, чтобы изменить таймеры, вы должны прислать ical-ссылку на свой календарь!")
|
||||||
|
|
||||||
|
|
||||||
|
@dp.message_handler(commands=['stop_alarm'])
|
||||||
|
async def daily_up(message: types.Message):
|
||||||
|
user_id = du.get_user_id(int(message.chat.id))
|
||||||
|
|
||||||
|
if dc.clock_exists(user_id):
|
||||||
|
if dc.get_status2(user_id):
|
||||||
|
await message.answer("Второе уведомление выключено!")
|
||||||
|
else:
|
||||||
|
await message.answer("Второе уведомление включено!")
|
||||||
|
|
||||||
|
dc.update_status2(user_id)
|
||||||
|
else:
|
||||||
|
await message.answer("Для взаимодействия с событиями вы должны прислать ical-ссылку на календарь!")
|
||||||
|
|
||||||
|
|
||||||
|
# ЗАГРУЗКА ССЫЛКИ
|
||||||
|
@dp.message_handler(content_types=['text'])
|
||||||
|
async def downloading_file_ics(message: types.Message):
|
||||||
|
user_id = du.get_user_id(int(message.chat.id))
|
||||||
|
|
||||||
|
if message.text[:5] == "https":
|
||||||
|
try:
|
||||||
|
wget.download(message.text, f'../data/icals/{str(user_id)}_new.ics')
|
||||||
|
|
||||||
|
try:
|
||||||
|
os.remove(f'../data/icals/{str(user_id)}.ics')
|
||||||
|
except FileNotFoundError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
os.rename(f'../data/icals/{str(user_id)}_new.ics', f'../data/icals/{str(user_id)}.ics')
|
||||||
|
|
||||||
|
time_zone = message.text.split("=")[-1]
|
||||||
|
if not du.url_exists(user_id):
|
||||||
|
du.add_url(user_id, message.text, time_zone)
|
||||||
|
dc.add_clock(user_id)
|
||||||
|
else:
|
||||||
|
du.update_url(user_id, message.text, time_zone)
|
||||||
|
|
||||||
|
await message.answer("Ссылка успешно добавлена! Уведомления уже включены!")
|
||||||
|
except Exception:
|
||||||
|
await message.answer("Ошибка скачивания! Проверьте правильность ссылки и пришлите ещё раз")
|
||||||
|
|
||||||
|
if 'reply_to_message' in message and dc.clock_exists(user_id):
|
||||||
|
text = "Для изменения времени вам надо в ответ на это сообщение прислать два числа через " \
|
||||||
|
"пробел: разница времени первого и второго таймера по ходу времени соответственно"
|
||||||
|
|
||||||
|
if message.reply_to_message.caption == text:
|
||||||
|
alarm_new = message.text.split()
|
||||||
|
|
||||||
|
if int(alarm_new[0]) < 60 and int(alarm_new[1]) < 60:
|
||||||
|
dc.update_alarm1(user_id, int(alarm_new[0]))
|
||||||
|
dc.update_alarm2(user_id, int(alarm_new[1]))
|
||||||
|
|
||||||
|
await message.answer("Время отправки уведомлений успешно обновлено!")
|
||||||
|
else:
|
||||||
|
await message.answer("Время отправки уведомлений должно быть меньше 60 минут!")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# ПРОВЕРКА НА СОБЫТИЕ
|
||||||
|
async def alarm(wait_for):
|
||||||
|
while True:
|
||||||
|
await asyncio.sleep(wait_for)
|
||||||
|
|
||||||
|
users_id = du.all_users()
|
||||||
|
for user_id in users_id:
|
||||||
|
user_id = user_id[0]
|
||||||
|
|
||||||
|
if dc.clock_exists(user_id):
|
||||||
|
if du.get_status(user_id):
|
||||||
|
events = sorted(text_ical(user_id, du.get_tz(user_id)))
|
||||||
|
tg_id = str(du.get_first_user_id(user_id))
|
||||||
|
|
||||||
|
start = dc.get_start(user_id)
|
||||||
|
daily = dc.get_daily(user_id)
|
||||||
|
alarm = dc.get_alarm(user_id)
|
||||||
|
|
||||||
|
alarm2_status = dc.get_status2(user_id)
|
||||||
|
|
||||||
|
today = dt_now(du.get_tz(user_id)).date()
|
||||||
|
time_check = dt_now(du.get_tz(user_id)).time()
|
||||||
|
|
||||||
|
# ДЛЯ DAILY
|
||||||
|
counter = 0
|
||||||
|
txt = "<b>События сегодня</b>\n\n"
|
||||||
|
|
||||||
|
delta_daily1 = time(hour=8, minute=0)
|
||||||
|
delta_daily2 = time(hour=8, minute=1)
|
||||||
|
# --------------------------------
|
||||||
|
|
||||||
|
for event in events:
|
||||||
|
if event[0] == today:
|
||||||
|
d_event = datetime.combine(today, event[1])
|
||||||
|
|
||||||
|
if daily and delta_daily1 <= time_check < delta_daily2:
|
||||||
|
counter += 1
|
||||||
|
txt += message_form(counter, event[3])
|
||||||
|
|
||||||
|
delta_start = delta_time(d_event, 1, 0)
|
||||||
|
if start and delta_start[0] < time_check <= delta_start[1]:
|
||||||
|
await bot.send_message(chat_id=tg_id, parse_mode=ParseMode.HTML,
|
||||||
|
text=f"<b>Событие начинается!</b>\n\n" + message_form(0, event[3]))
|
||||||
|
|
||||||
|
delta_alarm1 = delta_time(d_event, alarm[0], alarm[0] - 1)
|
||||||
|
if delta_alarm1[0] < time_check <= delta_alarm1[1]:
|
||||||
|
await bot.send_message(chat_id=tg_id, parse_mode=ParseMode.HTML,
|
||||||
|
text=f"<b>Напоминаю!</b>\n<i>Через {alarm[0]} минут "
|
||||||
|
f"будет событие:</i>\n\n{message_form(0, event[3])}")
|
||||||
|
|
||||||
|
if alarm2_status:
|
||||||
|
delta_alarm2 = delta_time(d_event, alarm[1], alarm[1] - 1)
|
||||||
|
if delta_alarm2[0] < time_check <= delta_alarm2[1]:
|
||||||
|
await bot.send_message(chat_id=tg_id, parse_mode=ParseMode.HTML,
|
||||||
|
text=f"<b>Напоминаю!</b>\n<i>Через {alarm[1]} минут "
|
||||||
|
f"будет событие:</i>\n\n{message_form(0, event[3])}")
|
||||||
|
|
||||||
|
if daily and delta_daily1 <= time_check < delta_daily2:
|
||||||
|
if counter:
|
||||||
|
await bot.send_message(chat_id=tg_id, parse_mode=ParseMode.HTML,
|
||||||
|
text=txt)
|
||||||
|
else:
|
||||||
|
await bot.send_message(chat_id=tg_id, parse_mode=ParseMode.HTML,
|
||||||
|
text=f"Сегодня событий <b>нет</b>")
|
||||||
|
|
||||||
|
|
||||||
|
async def update(wait_for):
|
||||||
|
while True:
|
||||||
|
await asyncio.sleep(wait_for)
|
||||||
|
|
||||||
|
users_id = du.all_users()
|
||||||
|
for user_id in users_id:
|
||||||
|
user_id = user_id[0]
|
||||||
|
|
||||||
|
if du.url_exists(user_id):
|
||||||
|
if du.get_status(user_id):
|
||||||
|
wget.download(du.get_url(user_id), f'../data/icals/{str(user_id)}_new.ics')
|
||||||
|
|
||||||
|
os.remove(f'../data/icals/{str(user_id)}.ics')
|
||||||
|
os.rename(f'../data/icals/{str(user_id)}_new.ics', f'../data/icals/{str(user_id)}.ics')
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
loop = asyncio.get_event_loop()
|
||||||
|
loop.create_task(alarm(60)) # ПРОВЕРКА КАЖДУЮ 1 МИНУТУ
|
||||||
|
loop.create_task(update(1620)) # ПРОВЕРКА КАЖДУЮ 27 МИНУТУ
|
||||||
|
executor.start_polling(dp, skip_updates=True)
|
||||||
1
code/config.py
Normal file
1
code/config.py
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
TOKEN = "**********:***************************"
|
||||||
68
code/script.py
Normal file
68
code/script.py
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
from datetime import datetime, time
|
||||||
|
import icalendar
|
||||||
|
|
||||||
|
|
||||||
|
def text_ical(user_id, tz):
|
||||||
|
date = dt_now(tz)
|
||||||
|
path = f'../data/icals/{user_id}.ics'
|
||||||
|
|
||||||
|
e = open(path, 'rb')
|
||||||
|
|
||||||
|
ecal = icalendar.Calendar.from_ical(e.read())
|
||||||
|
events = []
|
||||||
|
|
||||||
|
for i, component in enumerate(ecal.walk()):
|
||||||
|
if component.name == "VEVENT":
|
||||||
|
|
||||||
|
dt_start = component.decoded("dtstart")
|
||||||
|
dt_start.replace(tzinfo=None)
|
||||||
|
dt_start = dt_start.astimezone(tz)
|
||||||
|
|
||||||
|
dt_end = component.decoded("dtend")
|
||||||
|
dt_end.replace(tzinfo=None)
|
||||||
|
dt_end = dt_end.astimezone(tz)
|
||||||
|
|
||||||
|
if date.date() == component.decoded("dtstart").date():
|
||||||
|
org = component.get("organizer")
|
||||||
|
desc = component.get("description")
|
||||||
|
|
||||||
|
event = {"name": component.get('summary'), "desc": desc if desc else "отсутствует",
|
||||||
|
"org": org if org else "не назначен", "datetime": [dt_start, dt_end]}
|
||||||
|
|
||||||
|
events.append([dt_start.date(), dt_start.time(), i, event])
|
||||||
|
e.close()
|
||||||
|
|
||||||
|
return events
|
||||||
|
|
||||||
|
|
||||||
|
def message_form(k, event):
|
||||||
|
txt = ""
|
||||||
|
|
||||||
|
if k:
|
||||||
|
txt += f"-------\n"
|
||||||
|
txt += f"<b>{k}. {event['name']}</b>\n"
|
||||||
|
else:
|
||||||
|
txt += f"<b>{event['name']}</b>\n"
|
||||||
|
|
||||||
|
txt += f"<b>Описание:</b> {event['desc']}\n"
|
||||||
|
txt += f"<b>Организатор:</b> {event['org']}\n\n"
|
||||||
|
txt += f"<b>Начало: {event['datetime'][0].strftime('%H:%M - %d.%m.%Y года')}</b>\n"
|
||||||
|
txt += f"<b>Конец: {event['datetime'][1].strftime('%H:%M - %d.%m.%Y года')}</b>\n"
|
||||||
|
|
||||||
|
return txt
|
||||||
|
|
||||||
|
|
||||||
|
def delta_time(d_event, start, end):
|
||||||
|
d_start = datetime.combine(d_event.date(), time(hour=0, minute=start))
|
||||||
|
d_end = datetime.combine(d_event.date(), time(hour=0, minute=end))
|
||||||
|
|
||||||
|
zero = datetime.combine(d_event.date(), time(0, 0, 0, 0))
|
||||||
|
|
||||||
|
dt_start = zero + (d_event - d_start)
|
||||||
|
dt_end = zero + (d_event - d_end)
|
||||||
|
|
||||||
|
return [dt_start.time(), dt_end.time()]
|
||||||
|
|
||||||
|
|
||||||
|
def dt_now(tz):
|
||||||
|
return datetime.now(tz=tz)
|
||||||
159
code/sql.py
Normal file
159
code/sql.py
Normal file
|
|
@ -0,0 +1,159 @@
|
||||||
|
from pytz import timezone
|
||||||
|
import sqlite3
|
||||||
|
|
||||||
|
|
||||||
|
class Users:
|
||||||
|
def __init__(self, database):
|
||||||
|
"""Подключаемся к БД и сохраняем курсор соединения"""
|
||||||
|
self.connection = sqlite3.connect(database)
|
||||||
|
self.cursor = self.connection.cursor()
|
||||||
|
|
||||||
|
# КОМАНДЫ USER
|
||||||
|
def user_exists(self, user_id):
|
||||||
|
"""Проверяем, есть ли уже пользователь в базе"""
|
||||||
|
with self.connection:
|
||||||
|
result = self.cursor.execute(f'SELECT * FROM `user` WHERE `user_id` = ?', (user_id,)).fetchall()
|
||||||
|
return bool(len(result))
|
||||||
|
|
||||||
|
def all_users(self):
|
||||||
|
"""Список айди"""
|
||||||
|
with self.connection:
|
||||||
|
return self.cursor.execute(f'SELECT `id` FROM `user`').fetchall()
|
||||||
|
|
||||||
|
def add_user(self, user_id):
|
||||||
|
"""Добавляем нового пользователя"""
|
||||||
|
with self.connection:
|
||||||
|
return self.cursor.execute(f"INSERT INTO `user` (`user_id`) VALUES(?)", (user_id,))
|
||||||
|
|
||||||
|
def get_user_id(self, user_id):
|
||||||
|
"""Получаем короткое айди юзера"""
|
||||||
|
with self.connection:
|
||||||
|
return self.cursor.execute(f'SELECT `id` FROM `user` WHERE `user_id` = ?', (user_id,)).fetchone()[0]
|
||||||
|
|
||||||
|
def get_first_user_id(self, user_id):
|
||||||
|
"""Получаем длинное айди юзера"""
|
||||||
|
with self.connection:
|
||||||
|
return self.cursor.execute(f'SELECT `user_id` FROM `user` WHERE `id` = ?', (user_id,)).fetchone()[0]
|
||||||
|
|
||||||
|
# КОМАНДЫ URL
|
||||||
|
def url_exists(self, user_id):
|
||||||
|
"""Проверяем, есть ли данные уже в базе"""
|
||||||
|
with self.connection:
|
||||||
|
result = self.cursor.execute(f'SELECT * FROM `url` WHERE `user_id` = ?', (user_id,)).fetchall()
|
||||||
|
return bool(len(result))
|
||||||
|
|
||||||
|
def add_url(self, user_id, url_ical, time_zone):
|
||||||
|
"""Добавляем ссылку на календарь"""
|
||||||
|
with self.connection:
|
||||||
|
return self.cursor.execute(f"INSERT INTO `url` (`user_id`, `url_ical`, `time_zone`) VALUES(?, ?, ?)",
|
||||||
|
(user_id, url_ical, time_zone))
|
||||||
|
|
||||||
|
def update_status(self, user_id):
|
||||||
|
"""Обновляем статус рассылки уведомлений"""
|
||||||
|
with self.connection:
|
||||||
|
status = self.cursor.execute(f'SELECT `status` FROM `url` WHERE `user_id` = ?', (user_id,)).fetchone()[0]
|
||||||
|
return self.cursor.execute("UPDATE `url` SET `status` = ? WHERE `user_id` = ?", (not status, user_id))
|
||||||
|
|
||||||
|
def update_url(self, user_id, url_ical, time_zone):
|
||||||
|
"""Обновляем ссылку и часовой пояс в базе"""
|
||||||
|
with self.connection:
|
||||||
|
return self.cursor.execute("UPDATE `url` SET `url_ical` = ?, `time_zone` = ? WHERE `user_id` = ?",
|
||||||
|
(url_ical, time_zone, user_id))
|
||||||
|
|
||||||
|
def get_status(self, user_id):
|
||||||
|
"""Получаем статус работы"""
|
||||||
|
with self.connection:
|
||||||
|
return self.cursor.execute(f'SELECT `status` FROM `url` WHERE `user_id` = ?', (user_id,)).fetchone()[0]
|
||||||
|
|
||||||
|
def get_url(self, user_id):
|
||||||
|
"""Получаем ссылку на календарь"""
|
||||||
|
with self.connection:
|
||||||
|
return self.cursor.execute(f'SELECT `url_ical` FROM `url` WHERE `user_id` = ?', (user_id,)).fetchone()[0]
|
||||||
|
|
||||||
|
def get_tz(self, user_id):
|
||||||
|
"""Получаем указанный в календаре часовой пояс"""
|
||||||
|
with self.connection:
|
||||||
|
return timezone(self.cursor.execute(f'SELECT `time_zone` FROM `url` WHERE `user_id` = ?',
|
||||||
|
(user_id,)).fetchone()[0])
|
||||||
|
|
||||||
|
# ЗАКРЫТИЕ ВЫЗОВА
|
||||||
|
def close(self):
|
||||||
|
"""Закрываем соединение с БД"""
|
||||||
|
self.connection.close()
|
||||||
|
|
||||||
|
|
||||||
|
class Clock:
|
||||||
|
def __init__(self, database):
|
||||||
|
"""Подключаемся к БД и сохраняем курсор соединения"""
|
||||||
|
self.connection = sqlite3.connect(database)
|
||||||
|
self.cursor = self.connection.cursor()
|
||||||
|
|
||||||
|
# КОМАНДЫ ALARM
|
||||||
|
def clock_exists(self, user_id):
|
||||||
|
"""Проверяем, есть ли данные уже в базе"""
|
||||||
|
with self.connection:
|
||||||
|
result = self.cursor.execute(f'SELECT * FROM `alarm` WHERE `user_id` = ?', (user_id,)).fetchall()
|
||||||
|
return bool(len(result))
|
||||||
|
|
||||||
|
def add_clock(self, user_id):
|
||||||
|
"""Добавляем параметры уведомления"""
|
||||||
|
with self.connection:
|
||||||
|
return self.cursor.execute(f"INSERT INTO `alarm` (`user_id`, `alarm_1`, `alarm_2`) VALUES(?, ?, ?)",
|
||||||
|
(user_id, 15, 5))
|
||||||
|
|
||||||
|
# КОМАНДЫ ПОЛУЧЕНИЯ ССЫЛОК
|
||||||
|
def get_alarm(self, user_id):
|
||||||
|
"""Получаем задержки таймера"""
|
||||||
|
with self.connection:
|
||||||
|
return self.cursor.execute(f'SELECT `alarm_1`, `alarm_2` FROM `alarm` WHERE `user_id` = ?',
|
||||||
|
(user_id,)).fetchone()
|
||||||
|
|
||||||
|
def get_start(self, user_id):
|
||||||
|
"""Получаем статус уведомления в момент исполнения"""
|
||||||
|
with self.connection:
|
||||||
|
return self.cursor.execute(f'SELECT `start` FROM `alarm` WHERE `user_id` = ?', (user_id,)).fetchone()[0]
|
||||||
|
|
||||||
|
def get_daily(self, user_id):
|
||||||
|
"""Получаем статус ежедневного уведомления"""
|
||||||
|
with self.connection:
|
||||||
|
return self.cursor.execute(f'SELECT `daily` FROM `alarm` WHERE `user_id` = ?', (user_id,)).fetchone()[0]
|
||||||
|
|
||||||
|
def get_status2(self, user_id):
|
||||||
|
"""Получаем статус отправки второго уведомления"""
|
||||||
|
with self.connection:
|
||||||
|
return self.cursor.execute(f'SELECT `status_2` FROM `alarm` WHERE `user_id` = ?', (user_id,)).fetchone()[0]
|
||||||
|
|
||||||
|
# КОМАНДЫ ОБНОВЛЕНИЯ БУЛЕВЫХ СТАТУСОВ
|
||||||
|
def update_daily(self, user_id):
|
||||||
|
"""Обновляем статус ежедневного уведомления"""
|
||||||
|
with self.connection:
|
||||||
|
daily = self.cursor.execute(f'SELECT `daily` FROM `alarm` WHERE `user_id` = ?', (user_id,)).fetchone()[0]
|
||||||
|
return self.cursor.execute("UPDATE `alarm` SET `daily` = ? WHERE `user_id` = ?", (not daily, user_id))
|
||||||
|
|
||||||
|
def update_start(self, user_id):
|
||||||
|
"""Обновляем статус уведомления в момент исполнения"""
|
||||||
|
with self.connection:
|
||||||
|
start = self.cursor.execute(f'SELECT `start` FROM `alarm` WHERE `user_id` = ?', (user_id,)).fetchone()[0]
|
||||||
|
return self.cursor.execute("UPDATE `alarm` SET `start` = ? WHERE `user_id` = ?", (not start, user_id))
|
||||||
|
|
||||||
|
# КОМАНДЫ ОБНОВЛЕНИЯ ВРЕМЕННОГО ДИАПАЗОНА
|
||||||
|
def update_alarm1(self, user_id, alarm_1):
|
||||||
|
"""Обновляем время первого оповещения"""
|
||||||
|
with self.connection:
|
||||||
|
return self.cursor.execute("UPDATE `alarm` SET `alarm_1` = ? WHERE `user_id` = ?", (alarm_1, user_id))
|
||||||
|
|
||||||
|
def update_alarm2(self, user_id, alarm_2):
|
||||||
|
"""Обновляем время второго оповещения"""
|
||||||
|
with self.connection:
|
||||||
|
return self.cursor.execute("UPDATE `alarm` SET `alarm_2` = ? WHERE `user_id` = ?", (alarm_2, user_id))
|
||||||
|
|
||||||
|
def update_status2(self, user_id):
|
||||||
|
"""Обновляем статус отправки второго уведомления"""
|
||||||
|
with self.connection:
|
||||||
|
status_2 = self.cursor.execute(f'SELECT `status_2` FROM `alarm` WHERE `user_id` = ?', (user_id,)).fetchone()[0]
|
||||||
|
return self.cursor.execute("UPDATE `alarm` SET `status_2` = ? WHERE `user_id` = ?", (not status_2, user_id))
|
||||||
|
|
||||||
|
# ЗАКРЫТИЕ ВЫЗОВА
|
||||||
|
def close(self):
|
||||||
|
"""Закрываем соединение с БД"""
|
||||||
|
self.connection.close()
|
||||||
386
data/icals/1.ics
Normal file
386
data/icals/1.ics
Normal file
|
|
@ -0,0 +1,386 @@
|
||||||
|
BEGIN:VCALENDAR
|
||||||
|
PRODID:-//Yandex LLC//Yandex Calendar//EN
|
||||||
|
VERSION:2.0
|
||||||
|
CALSCALE:GREGORIAN
|
||||||
|
METHOD:PUBLISH
|
||||||
|
X-WR-TIMEZONE:Europe/Samara
|
||||||
|
X-WR-CALNAME:Привет
|
||||||
|
BEGIN:VTIMEZONE
|
||||||
|
TZID:Asia/Krasnoyarsk
|
||||||
|
TZURL:http://tzurl.org/zoneinfo/Asia/Krasnoyarsk
|
||||||
|
X-LIC-LOCATION:Asia/Krasnoyarsk
|
||||||
|
BEGIN:STANDARD
|
||||||
|
TZOFFSETFROM:+061126
|
||||||
|
TZOFFSETTO:+0600
|
||||||
|
TZNAME:+06
|
||||||
|
DTSTART:19200106T000000
|
||||||
|
RDATE:19200106T000000
|
||||||
|
END:STANDARD
|
||||||
|
BEGIN:STANDARD
|
||||||
|
TZOFFSETFROM:+0600
|
||||||
|
TZOFFSETTO:+0700
|
||||||
|
TZNAME:+07
|
||||||
|
DTSTART:19300621T000000
|
||||||
|
RDATE:19300621T000000
|
||||||
|
RDATE:19920119T020000
|
||||||
|
END:STANDARD
|
||||||
|
BEGIN:DAYLIGHT
|
||||||
|
TZOFFSETFROM:+0700
|
||||||
|
TZOFFSETTO:+0800
|
||||||
|
TZNAME:+08
|
||||||
|
DTSTART:19810401T000000
|
||||||
|
RDATE:19810401T000000
|
||||||
|
RDATE:19820401T000000
|
||||||
|
RDATE:19830401T000000
|
||||||
|
RDATE:19840401T000000
|
||||||
|
RDATE:19850331T020000
|
||||||
|
RDATE:19860330T020000
|
||||||
|
RDATE:19870329T020000
|
||||||
|
RDATE:19880327T020000
|
||||||
|
RDATE:19890326T020000
|
||||||
|
RDATE:19900325T020000
|
||||||
|
RDATE:19920329T020000
|
||||||
|
RDATE:19930328T020000
|
||||||
|
RDATE:19940327T020000
|
||||||
|
RDATE:19950326T020000
|
||||||
|
RDATE:19960331T020000
|
||||||
|
RDATE:19970330T020000
|
||||||
|
RDATE:19980329T020000
|
||||||
|
RDATE:19990328T020000
|
||||||
|
RDATE:20000326T020000
|
||||||
|
RDATE:20010325T020000
|
||||||
|
RDATE:20020331T020000
|
||||||
|
RDATE:20030330T020000
|
||||||
|
RDATE:20040328T020000
|
||||||
|
RDATE:20050327T020000
|
||||||
|
RDATE:20060326T020000
|
||||||
|
RDATE:20070325T020000
|
||||||
|
RDATE:20080330T020000
|
||||||
|
RDATE:20090329T020000
|
||||||
|
RDATE:20100328T020000
|
||||||
|
END:DAYLIGHT
|
||||||
|
BEGIN:STANDARD
|
||||||
|
TZOFFSETFROM:+0800
|
||||||
|
TZOFFSETTO:+0700
|
||||||
|
TZNAME:+07
|
||||||
|
DTSTART:19811001T000000
|
||||||
|
RDATE:19811001T000000
|
||||||
|
RDATE:19821001T000000
|
||||||
|
RDATE:19831001T000000
|
||||||
|
RDATE:19840930T030000
|
||||||
|
RDATE:19850929T030000
|
||||||
|
RDATE:19860928T030000
|
||||||
|
RDATE:19870927T030000
|
||||||
|
RDATE:19880925T030000
|
||||||
|
RDATE:19890924T030000
|
||||||
|
RDATE:19900930T030000
|
||||||
|
RDATE:19920927T030000
|
||||||
|
RDATE:19930926T030000
|
||||||
|
RDATE:19940925T030000
|
||||||
|
RDATE:19950924T030000
|
||||||
|
RDATE:19961027T030000
|
||||||
|
RDATE:19971026T030000
|
||||||
|
RDATE:19981025T030000
|
||||||
|
RDATE:19991031T030000
|
||||||
|
RDATE:20001029T030000
|
||||||
|
RDATE:20011028T030000
|
||||||
|
RDATE:20021027T030000
|
||||||
|
RDATE:20031026T030000
|
||||||
|
RDATE:20041031T030000
|
||||||
|
RDATE:20051030T030000
|
||||||
|
RDATE:20061029T030000
|
||||||
|
RDATE:20071028T030000
|
||||||
|
RDATE:20081026T030000
|
||||||
|
RDATE:20091025T030000
|
||||||
|
RDATE:20101031T030000
|
||||||
|
RDATE:20141026T020000
|
||||||
|
END:STANDARD
|
||||||
|
BEGIN:DAYLIGHT
|
||||||
|
TZOFFSETFROM:+0700
|
||||||
|
TZOFFSETTO:+0700
|
||||||
|
TZNAME:+07
|
||||||
|
DTSTART:19910331T020000
|
||||||
|
RDATE:19910331T020000
|
||||||
|
END:DAYLIGHT
|
||||||
|
BEGIN:STANDARD
|
||||||
|
TZOFFSETFROM:+0700
|
||||||
|
TZOFFSETTO:+0600
|
||||||
|
TZNAME:+06
|
||||||
|
DTSTART:19910929T030000
|
||||||
|
RDATE:19910929T030000
|
||||||
|
END:STANDARD
|
||||||
|
BEGIN:STANDARD
|
||||||
|
TZOFFSETFROM:+0700
|
||||||
|
TZOFFSETTO:+0800
|
||||||
|
TZNAME:+08
|
||||||
|
DTSTART:20110327T020000
|
||||||
|
RDATE:20110327T020000
|
||||||
|
END:STANDARD
|
||||||
|
END:VTIMEZONE
|
||||||
|
BEGIN:VTIMEZONE
|
||||||
|
TZID:Europe/Samara
|
||||||
|
TZURL:http://tzurl.org/zoneinfo/Europe/Samara
|
||||||
|
X-LIC-LOCATION:Europe/Samara
|
||||||
|
BEGIN:STANDARD
|
||||||
|
TZOFFSETFROM:+032020
|
||||||
|
TZOFFSETTO:+0300
|
||||||
|
TZNAME:+03
|
||||||
|
DTSTART:19190701T032020
|
||||||
|
RDATE:19190701T032020
|
||||||
|
END:STANDARD
|
||||||
|
BEGIN:STANDARD
|
||||||
|
TZOFFSETFROM:+0300
|
||||||
|
TZOFFSETTO:+0400
|
||||||
|
TZNAME:+04
|
||||||
|
DTSTART:19300621T000000
|
||||||
|
RDATE:19300621T000000
|
||||||
|
RDATE:19911020T030000
|
||||||
|
RDATE:20110327T020000
|
||||||
|
END:STANDARD
|
||||||
|
BEGIN:STANDARD
|
||||||
|
TZOFFSETFROM:+0400
|
||||||
|
TZOFFSETTO:+0400
|
||||||
|
TZNAME:+04
|
||||||
|
DTSTART:19350127T000000
|
||||||
|
RDATE:19350127T000000
|
||||||
|
END:STANDARD
|
||||||
|
BEGIN:DAYLIGHT
|
||||||
|
TZOFFSETFROM:+0400
|
||||||
|
TZOFFSETTO:+0500
|
||||||
|
TZNAME:+05
|
||||||
|
DTSTART:19810401T000000
|
||||||
|
RDATE:19810401T000000
|
||||||
|
RDATE:19820401T000000
|
||||||
|
RDATE:19830401T000000
|
||||||
|
RDATE:19840401T000000
|
||||||
|
RDATE:19850331T020000
|
||||||
|
RDATE:19860330T020000
|
||||||
|
RDATE:19870329T020000
|
||||||
|
RDATE:19880327T020000
|
||||||
|
RDATE:19920329T020000
|
||||||
|
RDATE:19930328T020000
|
||||||
|
RDATE:19940327T020000
|
||||||
|
RDATE:19950326T020000
|
||||||
|
RDATE:19960331T020000
|
||||||
|
RDATE:19970330T020000
|
||||||
|
RDATE:19980329T020000
|
||||||
|
RDATE:19990328T020000
|
||||||
|
RDATE:20000326T020000
|
||||||
|
RDATE:20010325T020000
|
||||||
|
RDATE:20020331T020000
|
||||||
|
RDATE:20030330T020000
|
||||||
|
RDATE:20040328T020000
|
||||||
|
RDATE:20050327T020000
|
||||||
|
RDATE:20060326T020000
|
||||||
|
RDATE:20070325T020000
|
||||||
|
RDATE:20080330T020000
|
||||||
|
RDATE:20090329T020000
|
||||||
|
END:DAYLIGHT
|
||||||
|
BEGIN:STANDARD
|
||||||
|
TZOFFSETFROM:+0500
|
||||||
|
TZOFFSETTO:+0400
|
||||||
|
TZNAME:+04
|
||||||
|
DTSTART:19811001T000000
|
||||||
|
RDATE:19811001T000000
|
||||||
|
RDATE:19821001T000000
|
||||||
|
RDATE:19831001T000000
|
||||||
|
RDATE:19840930T030000
|
||||||
|
RDATE:19850929T030000
|
||||||
|
RDATE:19860928T030000
|
||||||
|
RDATE:19870927T030000
|
||||||
|
RDATE:19880925T030000
|
||||||
|
RDATE:19920927T030000
|
||||||
|
RDATE:19930926T030000
|
||||||
|
RDATE:19940925T030000
|
||||||
|
RDATE:19950924T030000
|
||||||
|
RDATE:19961027T030000
|
||||||
|
RDATE:19971026T030000
|
||||||
|
RDATE:19981025T030000
|
||||||
|
RDATE:19991031T030000
|
||||||
|
RDATE:20001029T030000
|
||||||
|
RDATE:20011028T030000
|
||||||
|
RDATE:20021027T030000
|
||||||
|
RDATE:20031026T030000
|
||||||
|
RDATE:20041031T030000
|
||||||
|
RDATE:20051030T030000
|
||||||
|
RDATE:20061029T030000
|
||||||
|
RDATE:20071028T030000
|
||||||
|
RDATE:20081026T030000
|
||||||
|
RDATE:20091025T030000
|
||||||
|
END:STANDARD
|
||||||
|
BEGIN:DAYLIGHT
|
||||||
|
TZOFFSETFROM:+0400
|
||||||
|
TZOFFSETTO:+0400
|
||||||
|
TZNAME:+04
|
||||||
|
DTSTART:19890326T020000
|
||||||
|
RDATE:19890326T020000
|
||||||
|
RDATE:20100328T020000
|
||||||
|
END:DAYLIGHT
|
||||||
|
BEGIN:STANDARD
|
||||||
|
TZOFFSETFROM:+0400
|
||||||
|
TZOFFSETTO:+0300
|
||||||
|
TZNAME:+03
|
||||||
|
DTSTART:19890924T030000
|
||||||
|
RDATE:19890924T030000
|
||||||
|
RDATE:19900930T030000
|
||||||
|
RDATE:20101031T030000
|
||||||
|
END:STANDARD
|
||||||
|
BEGIN:DAYLIGHT
|
||||||
|
TZOFFSETFROM:+0300
|
||||||
|
TZOFFSETTO:+0400
|
||||||
|
TZNAME:+04
|
||||||
|
DTSTART:19900325T020000
|
||||||
|
RDATE:19900325T020000
|
||||||
|
END:DAYLIGHT
|
||||||
|
BEGIN:DAYLIGHT
|
||||||
|
TZOFFSETFROM:+0300
|
||||||
|
TZOFFSETTO:+0300
|
||||||
|
TZNAME:+03
|
||||||
|
DTSTART:19910331T020000
|
||||||
|
RDATE:19910331T020000
|
||||||
|
END:DAYLIGHT
|
||||||
|
BEGIN:STANDARD
|
||||||
|
TZOFFSETFROM:+0300
|
||||||
|
TZOFFSETTO:+0300
|
||||||
|
TZNAME:+03
|
||||||
|
DTSTART:19910929T030000
|
||||||
|
RDATE:19910929T030000
|
||||||
|
END:STANDARD
|
||||||
|
BEGIN:STANDARD
|
||||||
|
TZNAME:+04
|
||||||
|
TZOFFSETFROM:+0400
|
||||||
|
TZOFFSETTO:+0400
|
||||||
|
DTSTART:20101031T030000
|
||||||
|
END:STANDARD
|
||||||
|
END:VTIMEZONE
|
||||||
|
BEGIN:VEVENT
|
||||||
|
DTSTART;TZID=Asia/Krasnoyarsk:20240123T213000
|
||||||
|
DTEND;TZID=Asia/Krasnoyarsk:20240123T220000
|
||||||
|
SUMMARY:Собрание
|
||||||
|
UID:zwdqywax0s4lz9ybyr9yandex.ru
|
||||||
|
SEQUENCE:0
|
||||||
|
DTSTAMP:20240126T105030Z
|
||||||
|
CREATED:20240123T110608Z
|
||||||
|
DESCRIPTION:Очень важное
|
||||||
|
URL:https://calendar.yandex.ru/event?event_id=1980777684
|
||||||
|
TRANSP:OPAQUE
|
||||||
|
CATEGORIES:Привет
|
||||||
|
LAST-MODIFIED:20240123T110608Z
|
||||||
|
CLASS:PRIVATE
|
||||||
|
END:VEVENT
|
||||||
|
BEGIN:VEVENT
|
||||||
|
DTSTART;TZID=Asia/Krasnoyarsk:20240123T203000
|
||||||
|
DTEND;TZID=Asia/Krasnoyarsk:20240123T210000
|
||||||
|
SUMMARY:Без названия
|
||||||
|
UID:zwdqywax0sz8640h6m8yandex.ru
|
||||||
|
SEQUENCE:0
|
||||||
|
DTSTAMP:20240126T105030Z
|
||||||
|
CREATED:20240123T110935Z
|
||||||
|
URL:https://calendar.yandex.ru/event?event_id=1980779802
|
||||||
|
TRANSP:OPAQUE
|
||||||
|
CATEGORIES:Привет
|
||||||
|
LAST-MODIFIED:20240123T110935Z
|
||||||
|
CLASS:PRIVATE
|
||||||
|
END:VEVENT
|
||||||
|
BEGIN:VEVENT
|
||||||
|
DTSTART;TZID=Asia/Krasnoyarsk:20240123T190000
|
||||||
|
DTEND;TZID=Asia/Krasnoyarsk:20240123T193000
|
||||||
|
SUMMARY:Без названия
|
||||||
|
UID:zwdqywax0szm0iv8br3yandex.ru
|
||||||
|
SEQUENCE:0
|
||||||
|
DTSTAMP:20240126T105030Z
|
||||||
|
CREATED:20240123T110938Z
|
||||||
|
URL:https://calendar.yandex.ru/event?event_id=1980779831
|
||||||
|
TRANSP:OPAQUE
|
||||||
|
CATEGORIES:Привет
|
||||||
|
LAST-MODIFIED:20240123T110938Z
|
||||||
|
CLASS:PRIVATE
|
||||||
|
END:VEVENT
|
||||||
|
BEGIN:VEVENT
|
||||||
|
DTSTART;TZID=Asia/Krasnoyarsk:20240123T223000
|
||||||
|
DTEND;TZID=Asia/Krasnoyarsk:20240123T230000
|
||||||
|
SUMMARY:Без названия
|
||||||
|
UID:zwdqywax0t03d7xqp32yandex.ru
|
||||||
|
SEQUENCE:0
|
||||||
|
DTSTAMP:20240126T105030Z
|
||||||
|
CREATED:20240123T110941Z
|
||||||
|
URL:https://calendar.yandex.ru/event?event_id=1980779871
|
||||||
|
TRANSP:OPAQUE
|
||||||
|
CATEGORIES:Привет
|
||||||
|
LAST-MODIFIED:20240123T110941Z
|
||||||
|
CLASS:PRIVATE
|
||||||
|
END:VEVENT
|
||||||
|
BEGIN:VEVENT
|
||||||
|
DTSTART;TZID=Europe/Samara:20240124T163000
|
||||||
|
DTEND;TZID=Europe/Samara:20240124T170000
|
||||||
|
SUMMARY:Привет
|
||||||
|
UID:zwdqywax08ke3e4lgn57yandex.ru
|
||||||
|
SEQUENCE:0
|
||||||
|
DTSTAMP:20240126T105030Z
|
||||||
|
CREATED:20240124T090329Z
|
||||||
|
URL:https://calendar.yandex.ru/event?event_id=1981462656
|
||||||
|
TRANSP:OPAQUE
|
||||||
|
CATEGORIES:Привет
|
||||||
|
LAST-MODIFIED:20240124T090329Z
|
||||||
|
CLASS:PRIVATE
|
||||||
|
END:VEVENT
|
||||||
|
BEGIN:VEVENT
|
||||||
|
DTSTART;TZID=Europe/Samara:20240126T130000
|
||||||
|
DTEND;TZID=Europe/Samara:20240126T133000
|
||||||
|
SUMMARY:Новое событие
|
||||||
|
UID:zwdqywax25jvjlx7r4e9yandex.ru
|
||||||
|
SEQUENCE:0
|
||||||
|
DTSTAMP:20240126T105030Z
|
||||||
|
CREATED:20240126T080645Z
|
||||||
|
DESCRIPTION:Надо встретиться
|
||||||
|
URL:https://calendar.yandex.ru/event?event_id=1983061891
|
||||||
|
TRANSP:OPAQUE
|
||||||
|
CATEGORIES:Привет
|
||||||
|
LAST-MODIFIED:20240126T080645Z
|
||||||
|
CLASS:PRIVATE
|
||||||
|
END:VEVENT
|
||||||
|
BEGIN:VEVENT
|
||||||
|
DTSTART;TZID=Europe/Samara:20240126T153000
|
||||||
|
DTEND;TZID=Europe/Samara:20240126T160000
|
||||||
|
SUMMARY:Ещё одно новое событие
|
||||||
|
UID:zwdqywax25jy3fg604q4yandex.ru
|
||||||
|
SEQUENCE:0
|
||||||
|
DTSTAMP:20240126T105030Z
|
||||||
|
CREATED:20240126T080704Z
|
||||||
|
DESCRIPTION:Реально надо встретиться
|
||||||
|
URL:https://calendar.yandex.ru/event?event_id=1983062020
|
||||||
|
TRANSP:OPAQUE
|
||||||
|
CATEGORIES:Привет
|
||||||
|
LAST-MODIFIED:20240126T080704Z
|
||||||
|
CLASS:PRIVATE
|
||||||
|
END:VEVENT
|
||||||
|
BEGIN:VEVENT
|
||||||
|
DTSTART;TZID=Europe/Samara:20240127T153000
|
||||||
|
DTEND;TZID=Europe/Samara:20240127T160000
|
||||||
|
SUMMARY:Без названия
|
||||||
|
UID:zwdqywax25sz6nhk0zfyandex.ru
|
||||||
|
SEQUENCE:0
|
||||||
|
DTSTAMP:20240126T105030Z
|
||||||
|
CREATED:20240126T084915Z
|
||||||
|
URL:https://calendar.yandex.ru/event?event_id=1983093315
|
||||||
|
TRANSP:OPAQUE
|
||||||
|
CATEGORIES:Привет
|
||||||
|
LAST-MODIFIED:20240126T084915Z
|
||||||
|
CLASS:PRIVATE
|
||||||
|
END:VEVENT
|
||||||
|
BEGIN:VEVENT
|
||||||
|
DTSTART;TZID=Europe/Samara:20240126T140000
|
||||||
|
DTEND;TZID=Europe/Samara:20240126T143000
|
||||||
|
SUMMARY:Тут ещё одно событие
|
||||||
|
UID:zwdqywax26494cx3kbv7yandex.ru
|
||||||
|
SEQUENCE:0
|
||||||
|
DTSTAMP:20240126T105030Z
|
||||||
|
CREATED:20240126T094235Z
|
||||||
|
DESCRIPTION:Забей хуй на него
|
||||||
|
URL:https://calendar.yandex.ru/event?event_id=1983139091
|
||||||
|
TRANSP:OPAQUE
|
||||||
|
CATEGORIES:Привет
|
||||||
|
LAST-MODIFIED:20240126T094235Z
|
||||||
|
CLASS:PRIVATE
|
||||||
|
END:VEVENT
|
||||||
|
END:VCALENDAR
|
||||||
BIN
data/photo_edit_alarm.jpg
Normal file
BIN
data/photo_edit_alarm.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
BIN
db/clock.db
Normal file
BIN
db/clock.db
Normal file
Binary file not shown.
BIN
db/users.db
Normal file
BIN
db/users.db
Normal file
Binary file not shown.
Loading…
Add table
Reference in a new issue